Skip to content

Server operations

Logs, health checks, the storage warning and the errors zidane-server and its clients print, with their causes and fixes.

Logs#

The server writes its log to stderr. At start, it prints where it listens, then any notes and warnings:

Text
✓ zidane server listening on ws://0.0.0.0:4280 and /data/.zidane/server.sock (data /data/.zidane, pid 7)
· Stored the bootstrap token from ZIDANE_SERVER_BOOTSTRAP_TOKEN as tok_3f2a… "bootstrap". Revoke it once device tokens exist: zidane server token revoke bootstrap.
! warning: behind a proxy without trusted proxies: X-Forwarded-* headers from any peer are believed …
SourceShows
stderr, alwaysThe listening line, warnings, a broken token file, shutdown (zidane server: SIGTERM, shutting down)
stderr, with --verbose (or ZIDANE_SERVER_VERBOSE=1)Every connection, authentication, refusal and disconnect, as [server] and [ipc-ws] lines
server-audit.jsonlConnections, tokens, sync, installs: the audit log
server-audit.failures.jsonlRefused upgrades, aggregated per address and minute

Under systemd: journalctl -u zidane-server -f. In Docker: docker logs -f zidane.

Health#

CommandPrints on successExit
zidane-server healthok server "<name>" v<version> protocol <n> pid <pid> up <s>s0, else 1
zidane-server health --httpok http://127.0.0.1:4280/healthz0 on a 200, else 1
zidane-server wait-idleidle, or idle after <s>s0 once idle (or when no server answers), 1 when work is still going at --timeout (10 minutes by default)

wait-idle asks the host over the unix socket until no run, compaction, / command or background task is in flight. Open terminals do not count. Run it before a restart (an upgrade, a renewed certificate), because a restart cuts off running tool calls. daemon.info reports the same as activeWork.

health asks the host over the unix socket, without a token. --timeout <ms> bounds it (default 5000).

health --http requests GET /healthz on the configured port. When the server listens on every interface, the request goes to loopback. It does not check the TLS certificate. From another machine, run:

Terminal
curl -fsS https://zidane.example.com/healthz

Channels#

zidane-server channels check checks the channels config offline and exits 1 on errors. channels status lists the running server's channel integrations. channels reload makes the running server read its config again. It sends SIGHUP to the pid the server reports over its unix socket, so run it where the server runs (in a container, through docker exec). reload sends nothing when no channel runs. A server that started without channels exits on SIGHUP and needs a restart. If its config did not load, fix it and send SIGHUP yourself. See Channels.

Storage warning#

In a Linux container, the server looks at its mounts at start. If its data dir is not on a persistent mount, it prints this warning:

Text
! warning: the data dir is not on a persistent volume; it will be lost when the container is recreated (/data/.zidane is on an anonymous volume, a new one for each container). Mount a named volume or a host directory on it …

The cause in parentheses is one of three: the container's own filesystem, a tmpfs, or an anonymous volume. Docker makes an anonymous volume for the image's VOLUME when nothing is mounted, and a new one each time it creates the container. Mount a named volume or a host directory on /data. On Coolify, use Persistent Storage › Volume Mount.

Troubleshooting#

At start#

MessageCauseFix
Refusing to listen on 0.0.0.0 without TLS: device tokens and transcripts would cross the network in the clear.A non-loopback --host without TLS or a proxy--tls-cert and --tls-key, or --behind-proxy, or --host 127.0.0.1
TLS on the server and behind-proxy are exclusive: …A certificate with behind-proxy on, often the image's defaultZIDANE_SERVER_BEHIND_PROXY=0 and an empty ZIDANE_SERVER_TRUSTED_PROXIES, or drop the certificate
TLS needs both a certificate and a key: …Only one of the two is setSet both
… only applies behind a proxy: also set --behind-proxy …Trusted proxies without --behind-proxyAdd --behind-proxy, or clear the list
Invalid ZIDANE_SERVER_BOOTSTRAP_TOKEN: expected a token from `zidane server token generate` …Not a zds_ tokenPaste the output of token generate
ZIDANE_SERVER_BOOTSTRAP_TOKEN and ZIDANE_SERVER_BOOTSTRAP_TOKEN_FILE are both set: set one, not both.Both variablesKeep one
warning: … holds a revoked token …: ignored.The bootstrap value was revokedRemove the variable, or set a fresh token
Invalid <file> key "x": expected …, unknown key "x"A bad server.jsonFix the key. The message lists the known keys
Cannot read the TLS certificate <file>: ENOENT.A wrong path, or a file the server's user cannot readFix the path or its permissions
EADDRINUSEAnother process holds the portStop it, or change --port
warning: behind a proxy without trusted proxies …--behind-proxy with an empty listSet --trusted-proxies to your proxy
warning: the TLS certificate <file> expires on <date> …, … expired on …The certificate the server serves is within 14 days of its end, or past itRenew it, then restart once idle
warning: the TLS certificate or key changed on disk …A renewal: the server keeps serving the pair it read at startRestart once idle (zidane-server wait-idle, then restart)

When a client connects#

MessageCauseFix
token refused (401)A missing, unknown or revoked tokenCreate a token for the device
forbidden (403): the server only accepts connections through its HTTPS proxyBehind a proxy, a request that skipped it, or a proxy that sends no X-Forwarded-Proto: httpsConnect through the proxy's wss:// URL, or fix the proxy's headers
forbidden (403): the server only accepts connections from its trusted proxiesThe proxy's address is outside --trusted-proxiesAdd it
forbidden (403): this client's origin is not allowed by the server (allowedOrigins)A browser origin missing from the allowlistAdd it to ZIDANE_SERVER_ALLOWED_ORIGINS
the server redirects (301); not following it with the tokenAn http to https redirect, or a wrong pathUse the final wss:// URL
Refusing ws://host: the token would travel unencrypted.ws:// to a remote hostUse wss://, or an SSH tunnel to ws://127.0.0.1
Protocol version mismatch with <host>: the server speaks v13, this client v12. Upgrade the client. (status version mismatch)Different protocol versionsUpgrade the side it names. The client checks again every 5 minutes, or at once with Retry
A different server answers at <host>'s addressThe server was reinstalled, or the name points elsewhereRemove the host and add it again
too many connections or connection attempts (429)Too many upgrades from one address, or too many connections for one tokenClose stale windows. If the connections are yours, raise the caps
TLS failed: …A private or self-signed certificate this computer does not trustTrust it in the system's certificate store, or list it in NODE_EXTRA_CA_CERTS
… can be read by other users (mode 644) …A --token-file other users can readchmod 600 the file

While connected#

SymptomCauseFix
The connection closes with 1009A message over ZIDANE_SERVER_MAX_MESSAGE_BYTES (32 MiB)Smaller attachments, or raise the cap
Rate limit exceeded: slow down and retry. (-32012)Over 50 requests per second (burst 200) on one connectionBatch requests, or raise ZIDANE_SERVER_RATE_LIMIT
The reply is over … bytes (-32013)A reply too large for one messageAsk for less, for example a smaller limit on sessions.loadEvents
Long sessions open slowly over a slow linkTranscript pages go out uncompressedSet ZIDANE_SERVER_COMPRESS_LARGE_MESSAGES=1 (compressLargeMessages): messages of 64 KiB or more go out compressed to clients that accept it, at some CPU cost per message
A window drops and reloads its sessionMissed heartbeats, a slow consumer, or a server restartMake sure that the proxy's idle timeout is longer than 20 seconds. The window resumes without help
Tool approvals never comeTool approvals set to Ask or Model decision, and only a browser client connectedAnswer from the TUI or the desktop app (why)
A new session lands in an odd folderThe session got no folder, so it uses the first workspace root. A session started from a git project on your computer runs in a clone of it, <first root>/<repository name>Pick a folder in the new-session flow
A send from a local project fails with a clone errorThe server could not clone the project's origin: no git credentials there, no network, or another folder of that name in the first rootSet up git credentials on the server, or pick a folder in the new-session flow