Account & support
Troubleshooting
9 min read
Build went red? This page covers the most common failures and what to do about each. Every failed build records a machine-readable error_code on the dashboard build detail panel — start there, then find the matching section below.
Build error reference
error_code | What it means | Refunds the credit? |
|---|---|---|
BUILD_FAILED | Gradle / Capacitor / native toolchain rejected your code. | No — your code didn't compile. |
NO_APK | The build script claimed success but no APK landed in the expected output path. | No. |
ICON_DOWNLOAD_ERROR | We couldn't fetch the project icon URL you provided. | No — we did the work. |
SYSTEM_ERROR | Internal worker / API error. | Yes — platform fault. |
WORKER_TIMEOUT | Build ran past your tier's timeout (10 min Hobby, 30 min Starter). | Yes. |
WORKSPACE_ERROR | Worker couldn't set up the build environment. | Yes. |
DOWNLOAD_ERROR | Couldn't fetch your source archive from object storage. | Yes. |
KEYSTORE_DOWNLOAD_ERROR | Couldn't fetch the signing keystore. | Yes. |
KEYSTORE_DECRYPT_ERROR | Decrypting the per-org keystore envelope failed. | No (see Keystore decrypt error for why). |
EXEC_ERROR | A subprocess (Gradle, apksigner, etc.) returned non-zero from a system-side step. | Yes. |
UPLOAD_ERROR | Couldn't upload the finished APK back to object storage. | Yes. |
Platform faults (the "Yes" rows above) are tracked in billing.IsSystemFault and refund automatically. You should never need to email us for a credit refund on those — the dashboard credit balance reflects the refund within seconds of the build landing.
BUILD_FAILED — your code didn't compile
This is the single most common failure. By far. The build worker ran your code through npm install and then through the native build (Gradle for Android), and one of those steps returned non-zero.
Next step: open the build detail panel in the dashboard and read the log tail. We surface the last ~200 lines of stderr from the failing step, which is usually enough to spot the culprit.
Common patterns:
Cannot find module 'X'— a dependency is in your code but missing frompackage.json. Add it, re-bundle, re-upload.Module not found: Error: Can't resolve 'fs'(orpath,crypto) — Node-only modules referenced in a Capacitor/Vite bundle. Move that code to the native side or guard it.SDK location not found/ANDROID_HOME— almost always means the source bundle ships its owngradle.propertiesoverriding what our worker expects. Remove the line and re-upload.Execution failed for task ':app:processDebugResources'— typically a missing icon or splash asset. Cross-reference with AI Checks which flags this before you build.- Gradle version conflict (
Plugin requires Gradle X.Y) — Capacitor or RN updated their Gradle plugin past what yourgradle-wrapper.propertiespins. Bump the wrapper.
If the log tail isn't enough, the AI Checks panel from the same release usually has more context. The Compatibility scan in particular catches most BUILD_FAILED causes before they reach the build worker.
NO_APK — build claimed success but no APK landed
The Gradle process exited 0 but our worker couldn't find the expected APK at app/build/outputs/apk/release/app-release.apk (or the equivalent for your framework).
Almost always one of:
- Custom output path — your
build.gradlewrites to a non-default location. Either restore the default or tell us where to look in Settings > Project. - AAB instead of APK — you configured a
bundleReleaseinstead ofassembleRelease. Lunadeck v1.0 ships APKs only. - Multi-module project with no
appmodule — we look for theappGradle module. Rename or alias your main Android module toapp.
This error is charged because we did spin up the worker for the whole build — but if the cause turns out to be on us, email support@lunadeck.io and we'll refund manually.
ICON_DOWNLOAD_ERROR — icon URL unreachable
You supplied a project icon URL that returned a non-2xx (or didn't respond) when our worker fetched it. Quick fixes:
- Re-host the icon somewhere CDN-stable (your project's main asset host, S3 public, Imgur direct link).
- Check the URL works from
curloutside your local network. - Make sure the URL points at the image file, not a page wrapping it.
You can also clear the icon URL field entirely and we'll fall back to the default Lunadeck launcher icon for that build.
WORKER_TIMEOUT — build exceeded the tier limit
Build timeouts are tier-pinned:
- Hobby: 10 minutes
- Starter: 30 minutes
- Team / Business: 60 / 120 minutes (when those tiers go self-serve)
When your project genuinely needs more, three options:
- Upgrade — Starter triples the budget.
- Cache aggressively — see Cloud Build Engine > Caching for which paths persist between builds. Cold builds are slow; warm builds are usually 2–3× faster.
- Slim the bundle — large
node_modulesdirectories with unused frameworks (jQuery + React + Vue all installed, etc.) are a common timeout cause. The Performance check in AI Checks flags this.
WORKSPACE_ERROR / SYSTEM_ERROR — our infrastructure failed
These two error codes mean the failure happened outside your code — usually the worker container failed to provision, ran out of disk, or hit an internal RPC. Both refund automatically.
Rerun the build. If it fails twice in a row with the same code, check the status page — there may be an ongoing incident. If status is green and you're still hitting it, email support@lunadeck.io with the build ID so we can dig into the worker logs.
DOWNLOAD_ERROR — source bundle couldn't be fetched
Three causes, in order of likelihood:
- Source archive expired. Retention is 7 days for Hobby, 30 days for Starter. If you wait longer than your tier's retention between upload and build trigger, the retention sweeper purges the archive and the build fails on download. Re-upload the source and rebuild.
- MinIO availability issue. Rare. Refunds and retrying usually fixes it.
- Source upload was interrupted. If your
PUTto the upload URL didn't actually complete (network drop, browser tab closed), the size on disk won't match the declared size and download will fail. Re-upload from a stable connection.
This code refunds automatically.
KEYSTORE_DOWNLOAD_ERROR
Worker couldn't pull either the shared Lunadeck-debug keystore (Hobby) or your uploaded keystore (Starter+) from object storage. Rerun the build; this is essentially the same class of failure as DOWNLOAD_ERROR and refunds the same way.
KEYSTORE_DECRYPT_ERROR
We downloaded the encrypted keystore envelope but couldn't open it. Two causes:
- Master-key mismatch. Our worker's
KEYSTORE_MASTER_KEYdoesn't match what encrypted your envelope. This shouldn't happen in normal operation — if you see this, email support@lunadeck.io immediately with the build ID. We will refund this case manually (it's our infrastructure problem). - Tampered envelope. The on-disk envelope was modified after upload. Almost impossible in normal operation.
Note: this code does not auto-refund (see billing.IsSystemFault — the function excludes KEYSTORE_DECRYPT_ERROR from the platform-fault set out of caution against false-positive refunds). We refund manually on request.
EXEC_ERROR — a system-side subprocess returned non-zero
Different from BUILD_FAILED — this fires when an infrastructure step (apksigner invocation, watermark injection, file copy) failed, not when your build script failed. Refunded automatically. Rerun; if it persists, email support.
UPLOAD_ERROR — couldn't upload the finished APK
Your APK actually built, but the worker couldn't write it back to object storage. Refunded automatically. Rerunning usually resolves it; if status is green and it keeps happening, the build itself is producing a file we can't store (corrupted, way oversize) — email support with the build ID.
402 INSUFFICIENT_CREDITS — out of build credits
This is an API response, not a build error code — you'll see it when you click Build rather than after a build runs. See Account & Billing > When you run out for the upgrade or wait path.
Other situations
My build has been queued for ages and never starts
The build queue normally drains within seconds. If a build sits in queued for more than ~2 minutes:
- Check the status page —
build_queuedepth is reported there. - Hobby has 1 concurrent build per release. If you triggered two in quick succession, the second waits for the first to finish.
If the status page is green and your queue is short, the build will start. If it's been more than 10 minutes, email support@lunadeck.io with the build ID.
My AI Checks won't finish
AI Checks have their own queue separate from builds. They typically complete in 2–3 minutes for the full 6-check fan-out. If a check stays in running for longer, it'll eventually time out and surface as a "check failed" with a retryable banner — click Rerun on the specific check. AI Checks are advisory and never block your build, so you can always proceed without waiting.
My APK built but won't install on my device
Two common causes:
- Signature mismatch with an older install. Android refuses to upgrade an installed APK to one signed with a different certificate. Uninstall the previous version first. The most common version of this: you started on Hobby (Lunadeck-managed debug cert) and upgraded to Starter (your BYO cert) — Android sees the new APK as untrusted relative to the installed one. Uninstall, then install the new one.
- **
adb installcomplains "INSTALL_FAILED_VERSION_DOWNGRADE"** — you're installing an olderversionCodethan what's already installed. Bump theversionCode` in your build configuration and rebuild.
For Play Store-bound APKs specifically, see Certificate Vault > Bring your own keystore — Hobby builds use a shared debug certificate and cannot be uploaded to the Play Store.
Magic preview QR code won't scan
Magic preview deep-links are generated only for succeeded Android builds with a signed preview_url. If you see a placeholder card instead of a QR code on a build that succeeded, the most likely cause is the build is iOS-only (iOS doesn't support Magic preview at v1.0) or your environment has MAGIC_PREVIEW_JWT_SECRET unset — check the build's platform column.
The preview link expires when the build's expires_at is reached (7d Hobby, 30d Starter). Scan it before then.
Still stuck?
Email support@lunadeck.io with the build ID (a UUID printed at the top of the build detail panel) and a one-line description of what you were trying to do. We can pull the full worker log from your build ID.