Docs / Candor Deploy
Troubleshooting deploys: builds, crashes, and logs
Where build output and runtime logs live in the portal, what each deployment phase means, and how to fix the failures we see most — build errors, wrong ports, missing env vars, database connections, and billing suspensions.
When a deploy goes wrong, the answer is almost always already written down — in one of two logs. This guide shows you where they are, what the common failures look like, and how to fix them yourself before you ever need to open a ticket.
Everything here lives in the Deployments tab of your client area at my.candorhost.com. Open the app that’s misbehaving to see its tabs: Logs, Deployments, Usage, Environment, Domains, and Settings.
The two logs, and where they live
Build output is everything that happened while we turned your commit into a runnable app: cloning the repository, detecting the stack, installing dependencies, compiling. It’s on the Deployments tab — click any deployment in the history and it expands to show the build output. We save a copy the moment a build finishes, so the output of an old build is always there, success or failure. Output is capped at the last 2,000 lines; a chattier build is trimmed from the top with a visible marker, because the reason a build failed is always at the end.
Runtime logs are what your app printed after it started — the framework’s startup banner, request logs, stack traces. They’re on the Logs tab, live, refreshing every few seconds with the most recent lines. “No output yet” usually means the app hasn’t had a successful deploy to run — though an app killed before it could print anything shows the same.
One honest caveat: all logs pass through a filter that strips references to our internal infrastructure before you see them. Your app’s own output comes through; the filter only drops or rewrites lines about our machinery.
What the deployment phases mean
Every deployment in the history (and the progress stepper during a deploy) shows one of these phases:
| Phase | What it means |
|---|---|
| Queued | The deploy was accepted and a build is about to start. |
| Building | Your commit is being built into an image. |
| Deploying | The build succeeded; the new version is starting up. |
| Live | The new version — and only the new version — is serving requests. |
| Failed | The build didn’t complete. The build output says why. |
| Canceled | The deploy was stopped before it finished. |
“Live” is deliberately strict: we don’t call a deploy live while the previous version is still answering requests.
The build fails
Open the deployment’s build output and read from the bottom — the last few lines are the actual error. What you’ll usually find:
- A dependency or compile error — the same failure you’d get building the project on your own machine. Fix it locally, commit, and push — a connected repository builds again automatically on every push.
- The stack wasn’t recognized. Builds use Nixpacks to detect what your project is — Node, Python, Go, Ruby, PHP, or a static site. If detection fails, check that the files that identify your stack (
package.json,pyproject.toml,go.mod, and so on) are in the directory being built. In a monorepo, that’s the Root directory you set when creating the app — left blank, we build the repository root, which may be a directory that identifies nothing. If your project genuinely needs its own Dockerfile, you can opt in to one. - The build hit a limit. A build gets up to 2 CPUs, 2 GB of memory, 10 GB of scratch space, and 15 minutes. Almost every project fits comfortably; a build that ends abruptly near the 15-minute mark, or while downloading something enormous, has hit one of these.
More on builders, ports, and configuration: Builds and configuration.
It deployed, but the URL doesn’t answer
The most common cause, by a wide margin: the app isn’t listening on the port we expect. We set a PORT environment variable inside your container (default 8080), route traffic to that port, and health-check it by connecting to it. An app that hard-codes port 3000 fails all three.
The symptoms are distinctive. The deployment sits in Deploying and never reaches Live — that’s by design: the previous version keeps serving until the new one proves it’s up, so a broken deploy never takes down a working site. Or the app starts, fails its health check, and is restarted over and over.
The fix: read the port from the PORT environment variable instead of hard-coding one, and listen on all interfaces (0.0.0.0), not just localhost. Builds and configuration has the details.
It starts, then crashes
Watch the Logs tab — a crash-on-boot almost always prints its reason there. The usual suspects:
- A missing environment variable. Add it on the Environment tab, one
KEY=valueper line. Saved values apply on the next deploy — push again, or deploy a commit from the Deployments tab, after saving. - A database connection error. A few things to check, in order: a freshly created database takes a moment to generate its credentials, so an app deployed in the same minute may beat it — redeploy once the database’s Connect tab shows a connection URI. Databases are reachable only from the apps in your project, never from the internet, so the host in the URI won’t resolve from your laptop — that’s expected. And if you’re on Python with SQLAlchemy and psycopg 3, the URI scheme needs to be
postgresql+psycopg://rather than plainpostgresql://. The Attach a database control on the Environment tab writes the correct URI into your app asDATABASE_URL(REDIS_URLfor Redis) — then redeploy to apply. More in Databases on Candor Deploy. - Nothing in the logs at all, just restarts. That’s usually memory. Each service has a fixed memory size, enforced as a hard limit; an app that outgrows it is stopped and restarted, often without a useful message. The Usage tab shows live memory against the limit — if it sits near 100%, that’s your answer. If your app genuinely needs more memory, contact us and we’ll get it resized.
A quick escape hatch while you debug: the Rollback button next to any earlier deployment in the history rebuilds and redeploys that commit.
The account is suspended
If an invoice goes unpaid, the account is eventually suspended. The portal says so plainly: apps are paused, databases are paused, and deploying from the portal is refused with “Tenant is suspended; deploys are blocked.” A git push while suspended is quietly ignored — nothing builds until the account is restored. Nothing is deleted: your data, environment variables, and configuration all stay put. Settle the invoice in billing and everything is restored as it was.
When to contact us
If the logs don’t explain it, write to us — Candid Support response times apply. Include:
- The app’s name and its URL.
- The short commit SHA of the deployment in question (it’s in the history).
- The phase it’s stuck in, and the last few lines of the build output or runtime logs.
- What changed most recently — new dependency, new env var, new domain.
If your live app is down, we aim to respond within 1 hour during business hours (Monday–Friday, 9am–6pm ET). Everything else gets a first response within one business day. Our automated monitoring runs 24/7, and the uptime commitment — 99.9% monthly — is published in the SLA.
Something here wrong, unclear, or missing? Tell us — docs get fixed like bugs.