Troubleshooting
The top 7 common issues when self-hosting Concierto. Symptoms, causes, how to diagnose, how to fix.
Look up issues by symptom. Each entry gives you symptom / likely causes / how to diagnose / how to fix. If your situation isn't listed, open an issue on GitHub.
Daemon can't connect to the server
Symptom: concierto daemon's status command shows offline or connection refused; the server logs show no /api/daemon/register or /api/daemon/heartbeat requests. For how the daemon mechanism works, see Daemon and runtimes.
Likely causes:
CONCIERTO_SERVER_URLpoints at the wrong address, default isws://localhost:8080/ws; self-host must change it to your server address- Network / firewall blocking. The daemon and server aren't on the same network, or outbound traffic is blocked
- Token expired or invalid. You never ran
concierto login, or the PAT was revoked - Server rejected registration, the account you signed in with isn't in the target workspace (register returns 403)
- DNS resolution failure, the hostname doesn't resolve on the daemon machine
How to diagnose:
concierto daemon logs --lines 100 # look for daemon-side errors
echo $CONCIERTO_SERVER_URL # confirm the address is set
curl -i http://<server-host>:8080/health # hit the server directly
curl -i http://<server-host>:8080/readyz # include DB + migration readiness
cat ~/.concierto/config.json # verify api_token exists
concierto workspace list # confirm you're a member of the target workspaceHow to fix: address each cause above. The two most common fixes are changing CONCIERTO_SERVER_URL and restarting the daemon (concierto daemon restart) and signing in again (concierto logout && concierto login).
Tasks stuck in queued
Symptom: after assigning an issue to an agent, the issue status flips to in_progress immediately, but a long time passes with no sign of agent execution on the page; concierto daemon status shows the daemon online.
Likely causes (ordered by frequency):
- Agent concurrency limit reached, this agent's
max_concurrent_tasks(default 6) is fully occupied by other running tasks - Another task from the same agent is still running on the same issue, same agent × same issue is forced to run sequentially (prevents duplicate execution)
- Agent has been archived. After archival, new tasks still enqueue but can't be claimed, and they time out after 5 minutes (code-issue G-01)
- Daemon hasn't registered this runtime in the current workspace, restart the daemon or reselect the runtime in the UI
- Daemon disconnected, no heartbeat in the last 45 seconds.
daemon statusreportingonlinemay reflect a very recent disconnect
How to diagnose:
concierto daemon status --output json # runtime list + last_seen_at
concierto agent list # check agent archived state
concierto issue show <issue-id> # inspect task historyOn the server side (self-host), grep for "no_tasks" / "no_capacity" to see the claim outcome.
How to fix:
- Concurrency full → wait for running tasks to finish, or
concierto agent update <id> --max-concurrent-tasks 10to raise the ceiling - Same-issue serialization → wait for the previous task to finish, or reassign to a different agent
- Agent archived →
concierto agent restore <id> - Runtime not registered →
concierto daemon restart, and the daemon will re-register
WebSocket can't connect
Symptom: the browser console logs WebSocket is closed; the page doesn't show real-time updates (task progress, comments, inbox), and a refresh is needed to see them; backend tasks still execute.
Likely causes:
- Origin check failure, your frontend domain isn't in the server's CORS allowlist. The default allowlist only includes
localhost:3000/5173/5174; self-hosting on the public internet requiresFRONTEND_ORIGIN - Protocol mismatch, frontend on
https://needswss://; HTTP usesws:// - Reverse proxy doesn't enable WebSocket upgrade, Nginx / Envoy / HAProxy don't forward the
Upgradeheader by default - JWT cookie expired or missing, no re-sign-in after the 30-day expiry
How to diagnose:
- Browser DevTools → Network → filter by "WS" and check connection state and status code
- Grep server logs for
"rejected origin"/"websocket", an origin issue spells itself out curl -i http://<server-host>:8080/wsshould return101 Switching Protocols(with theUpgradeheader)
How to fix:
- Wrong origin → set
FRONTEND_ORIGIN=https://nstack.yourdomain.comin the server's.env(or comma-separatedCORS_ALLOWED_ORIGINS) and restart the server - Protocol mismatch → make sure
FRONTEND_ORIGIN's protocol matches the frontend's - Reverse proxy → in Nginx, add
proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; - Cookie expired → refresh the page and sign in again
Emails not received
Symptom: after submitting an email during sign-in or invite acceptance, neither the inbox nor the spam folder has the verification code.
Likely causes:
RESEND_API_KEYnot set, the server silently falls back and writes the code to its own stdout without error. Easy to trip over in production- Resend API key invalid / out of quota, server logs show
"failed to send verification code" RESEND_FROM_EMAIL's domain not verified in Resend, Resend refuses to send- Email was sent but flagged as spam by the recipient's ISP, check the Resend dashboard and the spam folder
How to diagnose:
- Grep server logs for
"[DEV] Verification code for". If present, Resend isn't configured and the code was written to stdout - Resend dashboard → Emails for send history
- Confirm
RESEND_FROM_EMAIL's domain appears in the Resend console's "Verified Domains" list
How to fix:
- Missing API key → follow Sign-in and signup configuration → How email works to configure and restart the server
- Domain not verified → run the DNS verification flow in the Resend console (add SPF / DKIM records)
- In an emergency (internal testing) → copy the code printed under
[DEV]from the server logs
Fixed local test code doesn't work
Symptom: on a self-hosted instance, you try to sign in with a fixed local test code such as 888888 and it's rejected with invalid or expired code.
Likely causes (mutually exclusive):
CONCIERTO_DEV_VERIFICATION_CODEis empty, fixed codes are disabled by defaultAPP_ENV=production, this is the correct production configuration; fixed local test codes are ignored in production- The configured code is not 6 digits, the shortcut only accepts a 6-digit value
How to diagnose:
cat .env | grep -E 'APP_ENV|CONCIERTO_DEV_VERIFICATION_CODE'
docker exec <container> env | grep -E 'APP_ENV|CONCIERTO_DEV_VERIFICATION_CODE'Check your inbox (including spam) for the real verification code.
How to fix:
- In production, leave
CONCIERTO_DEV_VERIFICATION_CODEempty, configure Resend and use real codes - For local development or internal testing, either copy the generated code from server logs or set
APP_ENV=developmentplusCONCIERTO_DEV_VERIFICATION_CODE=888888, never enable a fixed code on a public instance (see Sign-in and signup configuration → Fixed local testing codes)
Port conflicts
Symptom: concierto server or concierto daemon start fails with address already in use.
Likely causes:
- Server port taken (default
8080) - Daemon health port taken (default
19514, offset by a hash per profile) - Web dev server port conflict (
3000/5173) - Insufficient privileges for the port (binding a privileged port
< 1024requires sudo)
How to diagnose:
lsof -i :8080 # macOS / Linux
netstat -ano | findstr :8080 # WindowsHow to fix:
- Kill the conflicting process (
kill -9 <PID>), or change ports viaPORT=9000 - To use 80 / 443 → don't bind directly; put a reverse proxy (Nginx / Caddy) in front, forwarding to a high port
Where to find logs
| Component | Location | Command |
|---|---|---|
| Daemon | ~/.concierto/daemon.log (background mode) or foreground stdout | concierto daemon logs -f --lines 100 |
| Server (Docker) | Container stdout | docker logs -f <container> |
| Server (systemd) | journal | journalctl -u concierto-server -f |
| Frontend (dev) | Terminal running pnpm dev | Read directly |
| Frontend (browser) | DevTools → Console | Press F12 |
For more detailed daemon logs, move it from background to foreground: concierto daemon stop && concierto daemon start --foreground.