Troubleshooting deploys
A Vessl deploy runs in clear phases: clone → build → release (post-deploy) → canary health check → traffic swap. When something fails, the deploy logs (the deployment drawer) tell you which phase and why. This page maps the common failures to fixes.
Vessl health-checks the new version as a canary before swapping traffic. If any phase fails, your previous version keeps serving — so you can fix and redeploy without downtime.
Clone phase
could not read Username / "Repository not found"
Vessl can't authenticate to your repo. The GitHub App isn't installed on the
account that owns the repo, or its access was revoked.
- Re-connect under Integrations on the owning account/org (for
your-org/app, install onyour-org). - If you recently reconnected, Vessl auto-relinks to the new installation for the same account — just redeploy.
Clone times out on a very large repo Large histories can be slow to clone. Push a slimmer history, or contact support if you regularly deploy big monorepos.
Build phase
Nixpacks can't resolve your language/runtime version Nixpacks reads your project files to pick the toolchain. Make sure they agree:
| Stack | Where the version comes from |
|---|---|
| Node | package.json engines.node |
| PHP | composer.json require.php floor |
| Python | .python-version / pyproject.toml |
| Ruby | .ruby-version / Gemfile |
composer.json, not a UI settingNixpacks picks the PHP version from your composer.json require.php floor and
your lockfile. If your composer.lock was resolved against a higher PHP
than your require allows, composer install fails. Align require.php with
the PHP your lockfile actually needs, then commit both.
Unsupported Gradle version (modern Java/Spring)
Nixpacks doesn't support the newest Gradle. Pin a supported Gradle version in
your project, or build with a Dockerfile.
Build needs a flag or an env var at build time
- Add
--build-arg-style values with Build Args (passed to yourDockerfile). - Override the build with a Build Command when the default doesn't fit.
- Only env vars with public prefixes are baked into the image at build time; secrets (DB passwords, app keys) are injected at runtime, not build time.
Monorepo — wrong directory built
Set the Root Directory on the app to the subfolder that contains the app
(e.g. backend). Vessl builds from there.
Release (post-deploy) phase
The release command runs once, after build, before traffic swaps — this is where migrations belong. If it fails (e.g. a bad migration), the deploy fails and your old version stays live.
- Put migrations/seeders here, not in your start command. See Database migrations & seeding.
- A long first-time migration can exceed the readiness window — split it, or make sure the database add-on is ready first.
Canary / health-check phase
Health check fails with HTTP 500 The app built and started but errors on the health check. Usual causes:
- A missing environment variable — set it on the app and redeploy.
- A database it can't reach — confirm the add-on is attached and you redeployed after adding it (see Databases & add-ons).
- A runtime crash on startup — read your app's own error in the deploy logs.
Health check times out, but the app is slow to boot Frameworks that migrate or warm caches on boot can exceed the default window. Make sure heavy work runs in the release phase, not on every container start.
The wrong command runs / the app starts in a REPL
For Dockerfile builds, Vessl appends your Start Command to
docker run — make sure it actually starts your web server (e.g.
node server.js, gunicorn ...), not the image's default CMD. If you set no
start command, the image's CMD runs, which for some base images drops into an
interactive shell.
Deploy seems stuck
Deploys are processed by a dedicated worker and have generous timeouts. If a deploy looks stuck:
- Watch the live logs — long builds (heavy Rails/Vite, large Docker images) genuinely take several minutes.
- A first deploy holds a per-server lock for the build; a second deploy to the same server queues behind it.
- You can Cancel a deploy; the app returns to its previous state.
Still stuck?
Capture the failing phase and the last lines of the deploy logs, then reach out via the dashboard. The phase label plus your app's own error message is usually all that's needed to pinpoint it.