Troubleshooting
Symptoms, in the words you actually have in front of you, and what each one means.
Every failure here is explained in full somewhere else on this site. This page exists so it can be found by the string on the screen rather than by knowing which chapter it belongs to.
They are grouped by where you are standing when it happens.
The controller will not behave
A stream connects, returns 200, stays open, and delivers nothing. A reverse proxy is compressing or buffering a path that must be excluded from both. gzip holds a stream that never fills a buffer, and nothing in any log says so. This works perfectly against the port directly and fails only behind the proxy, so test at the real hostname. → Reverse proxy
Sign-in appears to succeed and then there is no session.
CONTROLLER_URL does not exactly match the origin the browser uses. better-auth derives cookie and
CSRF behaviour from it, so a scheme, a port or a trailing slash is enough.
→ Production runbook
The controller reports itself healthy but requests fail on the schema.
pnpm db:migrate was skipped. Migrations also run lazily on the first request that touches the
database, so a deploy that skips them passes its health check on the old schema and surfaces the
failure as a broken request instead of a failed deploy.
→ Migrations
controller did not exit cleanly, forcing in the journal.
Something new is holding the event loop past shutdown. The five-second fallback has covered for it.
Worth finding rather than living with.
→ Shutdown
Nothing ever leaves requested.
No worker is running. WORKER_ENABLED is off by default; run pnpm worker:tick, or turn it on.
→ Your first workspace
A command will not run
A CLI entrypoint fails before it does anything.
pnpm worker:tick, pnpm apikey:create and pnpm db:migrate all run files under dist/cli/.
Build them first:
pnpm build # both bundles
pnpm build:cli # just the CLIpnpm: command not found, part-way through a deploy.
Removing node_modules took pnpm's shims with it. Use corepack pnpm from that point on.
→ Deploying
A deploy builds and fails on a missing Vite.
The previous deploy ended with pnpm prune --prod, so pnpm install --frozen-lockfile reports
"Already up to date" and does not restore devDependencies. rm -rf node_modules first — this is
why the script does.
→ Deploying
Everything passes and the UI is an error box.
Hydration threw. check, typecheck, test and build do not load a page and cannot catch this.
A person has to open the site — especially after anything touching src/router.tsx, routing or SSR.
→ Deploying
An agent will not run
A POST /api/workspaces that used to work now fails validation.
harnessId is required, and there is no controller-wide default — picking an agent for the caller
would run one they did not choose.
Known limitation: no HTTP route lists configured agents. listLaunchableHarnesses is a server
function the browser calls, not a route, so a scripted caller cannot discover its id. Read it from
the Agents tab and put it in the script's configuration.
Nothing can be launched, and the form says so. No agent is configured, or every one is disabled. Nothing earlier in setup fails because of this: the controller starts, reports healthy, and passes every check. → The Agents tab
harness: this controller cannot run "<kind>".
The kind is not in this build's registry — usually a controller on older code than the one the
agent was configured on. The message lists what it does know.
→ Agents and harnesses
an opencode credential is JSON, like {"integration":…}.
opencode's credential is an envelope naming the integration, not a bare token. The value alone does
not say which integration it belongs to, and opencode stores that separately. Refused at save on
purpose: the alternative surfaces an hour later as an agent that cannot explain itself.
→ The Agents tab
An agent comes up unauthenticated, and editing its credential changes nothing. Credentials are written into a container at provision time. A fix applies to the next workspace; the running one has the old value in its filesystem. Fix it, then launch a new workspace.
A workspace will not build
destroy_ownership_mismatch, and the destroy has halted.
A container did not carry this controller's ownership marker, so it was deliberately left untouched.
Investigate by hand before retrying. Do not clear the flag to get past it.
→ Ownership
The first clone fails with a 403.
The Proxmox token does not hold VM.Audit and VM.Clone on the template VMID. A rebuild produces
a new VMID, and the grant does not follow it.
→ Proxmox setup
Provisioning fails at addressed.
The container booted and never got a DHCP lease. The controller polls the LXC interfaces endpoint
for whatever Proxmox reports, and ignores loopback, link-local, and anything outside the expected
subnet.
→ Networking
The agent answers every prompt with "Not logged in".
The runner started without its credentials. ~/.config/agent-env is hooked into .bashrc, which a
detached non-interactive process never reads, so the runner sources it explicitly. If that line is
missing the runner starts, listens, accepts prompts, and fails every one.
→ The agent runner
The runner dies at start with ERR_MODULE_NOT_FOUND.
The Agent SDK is not where the runner resolves it. It lives in the template's global root and is
reached through a node_modules symlink — NODE_PATH does not work, because it is a CommonJS
mechanism and node's ESM resolver ignores it. The template build verifies this before converting;
a template built any other way can pass every other check and fail here.
→ The agent runner
A template will not build
container has no DNS; check the bridge and DHCP.
The scratch container came up without a working network. Nothing after that point can install
anything.
→ Networking
<image> is not downloaded.
Bootstrap mode needs the base image present on the host. The script prints the exact
pveam download to run.
→ Proxmox setup
<vmid> is not a template.
The source for a rebuild must be an existing template. For the first template there is nothing to
clone: pass SOURCE_VMID= empty to build from a stock image instead.
→ Proxmox setup
The build stops at missing: <tool> and keeps the container.
Verification ran and something is not on the workspace user's PATH without a login shell, which is
how the controller reaches everything over SSH. Tooling installed under /root is the usual cause.
The container is kept precisely so it can be inspected:
pct start <vmid> && pct exec <vmid> -- bashWork seems to be stuck
A workspace will not reap. By design, and the timeline says which of the three exemptions applied: a blocked agent, uncommitted or unpushed work, or a workspace the controller could not inspect. Push or discard, and the hold releases on the spot rather than at the next pass. → Seeing the work
Containers show up as orphans after a database restore. Expected, and the reason nothing about orphans runs on a timer. A restored or lost database makes every live workspace look orphaned. The scan reports; it never destroys. → Ownership
Last updated on