-
Notifications
You must be signed in to change notification settings - Fork 0
Troubleshooting
Start here:
docker compose logs --tail 100 coordinatorThe coordinator fails closed and names the offending setting, so a boot failure is usually self-explaining. What follows is everything that goes wrong after it starts.
| Log says | Fix |
|---|---|
API_SECRET_KEY / JWT_SECRET_KEY is blank, too short, or … |
A secret in .env is empty or a default. ./scripts/gen-env.sh --force (rotates everything — sessions and agent tokens die). |
SECRET_ENCRYPTION_KEY must be set in production |
Same, but never regenerate this one if you have stored credentials — see Backup and restore. |
WRIT_PUBLIC_URL must be set in production |
Set it to the URL people open. ./scripts/deploy.sh does it for you. |
CORS_ORIGINS must list explicit https origins |
Replace * with your origin. |
Refusing to start: WEB_CONCURRENCY=N |
The coordinator is single-worker by design. Remove it; scale with more agents. |
The Host you are dialing is not on the allowlist. The response names the
rejected hostname.
Set WRIT_PUBLIC_URL to the URL people actually open and restart — its hostname
is trusted automatically. For an additional name (an alias, a wildcard), add it
under Settings → Network → Trusted hosts, which applies without a restart and
shows you the effective list.
docker compose --profile tls logs -f caddyIn order of likelihood:
-
DNS.
dig +short <domain>from the server. It must return this machine's public IP. - Inbound port 80 is blocked. ACME dials back on it; outbound-only firewall rules are not enough.
-
Something else holds port 80.
ss -ltnp 'sport = :80'— a distro nginx or Apache is the usual culprit. -
Rate-limited from debugging. Let's Encrypt allows 5 failures per hostname
per hour. Re-run with
--staginguntil it works, then once without.
FORWARDED_ALLOW_IPS does not cover the address your proxy connects from, so
every request looks like it came from the proxy and they all share one bucket.
With the bundled Caddy it is 127.0.0.1,172.16.0.0/12; with your own proxy it is
that proxy's address. Confirm by checking whether your audit log shows one
repeated IP for every user.
Nothing ever runs, everything queues. No agent is connected. The coordinator launches no browsers itself — see Connecting agents.
The agent starts but never appears in Fleet. It is dialing the wrong address.
Check WRIT_PUBLIC_URL, then re-enrol from Fleet → Connect a new agent — the
one-liner is generated from the current value, so an agent enrolled while it said
localhost keeps that address forever.
Agents drop after about a minute. Your reverse proxy is timing out the
WebSocket. On nginx you need the Upgrade/Connection headers and
proxy_read_timeout 300s — without the timeout it silently kills healthy agents.
The bundled Caddy does not have this problem.
An agent is online but only takes 2 jobs. That is the agent's own self-limit, not a coordinator cap. Click its slot meter in Fleet and set your own number.
PDFs and scanned pages come back empty. That agent cannot reach
doc-extract. It fails silently by design — it skips non-HTML content rather
than erroring. Agents on other machines need a routable
DOC_EXTRACT_URL; GET /api/fleet/connect-info shows what they are being handed.
My typing is not recorded. Click into the live browser view first. That click is what tells the recorder your keystrokes belong to the remote page rather than to the app's own toolbar; clicking any control in the recorder chrome hands focus back to the UI. You can tell it worked because the page responds as you type.
A fill step is missing but the click after it is there. Typed text is
recorded as one fill per field, emitted when you leave the field — Tab, Enter,
or clicking elsewhere. If you stopped the recording mid-field, that field never
closed.
The view freezes mid-navigation and nothing responds. This was a deadlock in agents built before this fix: a page navigating while an action was in flight could park the agent's worker threads against each other, wedging the session permanently. Update the agent. If you are on an older build, the session recovers only by reconnecting.
Everything is laggy while typing. Older agents sent one round-trip per keystroke. Update; keystrokes are now coalesced into one action per burst.
The app is up but a workflow's stored credential fails. Wrong
SECRET_ENCRYPTION_KEY — you restored data with a different key than it was
encrypted with. There is no recovery except the original key.
Runs are slow / the database is growing. Check
Settings → Data & retention; the default keeps 90 days. Screenshots stored as
base64 inside SQLite bloat it badly — make sure WRIT_FILES_DIR points at the
volume (the shipped Docker setup does this for you).
Include the version, how you deployed (bundled Caddy vs your own proxy), and:
docker compose logs --tail 100 coordinatorRedact .env values before pasting anything.
- Discussions — questions
- Issues — bugs
- Security problems: private reporting, never a public issue
usewrit/writ · AGPL-3.0-only · Issues · Discussions · Report a vulnerability
Getting started
Using it
Integrations
Operations
Reference