Troubleshooting
Diagnose COMA with coma doctor and coma endpoint doctor, and fix local fallback, busy ports, sync conflicts and reconnects.
Start with coma doctor
coma doctorcoma doctor checks the COMA installation, then the tools on your computer for traps that send commands somewhere other than the machine. Every check reports PASS, WARN or FAIL, with a hint after -> when something needs attention:
PASS version coma v0.1.0-rc.4-3-g07087e6 (07087e66d988), go1.27.1
PASS platform darwin is supported
PASS paths resolved from macos
PASS run-dir-socket-length endpoint socket paths fit (72 of 103 bytes)
PASS run-dir /Users/you/.coma/run is private (0700)
PASS config valid
PASS state-db schema v9
PASS state-writable write transaction succeeded
PASS current-context "default" exists
PASS local-fallback watching 2 local engine(s); none used while connected
WARN docker-credentials Docker's config.json names helpers that are not installed: docker-credential-osxkeychain; every image pull fails
-> remove credsStore/credHelpers from config.json or install the helper; tools that work around it with DOCKER_CONFIG lose the coma context
PASS docker-compose /usr/local/bin/docker-compose 2.39.3
PASS cli-routing connected to dev (docker)
PASS sync-helper /Users/you/.local/lib/coma/coma-sync (Mutagen)
13 passed, 1 warnings, 0 failed| Check | What it looks at |
|---|---|
version, platform | The build, and whether this OS is supported |
paths, run-dir-socket-length, run-dir | Where COMA keeps its files; socket paths fit the OS limit; the run directory is private |
config | The config file parses and its values are valid |
state-db, state-writable | The local state database opens, has a known schema and accepts writes |
current-context | The current COMA context exists |
local-fallback | Containers created on a local engine while you were connected |
docker-credentials | Credential helpers named in Docker's config.json are installed |
docker-compose | Every docker-compose on PATH, and whether any is Compose v1 |
cli-routing | While connected: whether the podman CLI (and a docker alias for it) reaches the same machine |
sync-helper | The coma-sync helper is installed and matches this COMA |
A WARN does not change the exit code. Any FAIL makes coma doctor exit with 10 (doctor_failed), so scripts and coding agents can act on it. coma doctor --json returns the same report as a DoctorReport.
Check one endpoint
An endpoint is the local socket that serves one machine's engine. Endpoints are named <machine>-<engine>; coma endpoint list shows them and their state (ready, reconnecting, degraded, stopped).
coma endpoint doctor dev-dockerchecks comad, the endpoint's state, that the engine answers through the socket, and whether the coma Docker context reaches it. It exits with 10 when a check fails.
To see what COMA did to the last container it handled:
coma endpoint doctor dev-docker --explain-lastThis shows the most recent request COMA intercepted: whether it was forwarded or refused (and why), and each change: ports moved to 127.0.0.1 on the machine, -P expanded, bind sources mapped to the synced copy, the Docker socket mapped, a start held until port mirrors were open. Request bodies are never stored or shown.
Common problems
Something sent Docker commands to a local engine. The usual causes:
DOCKER_HOSTorDOCKER_CONTEXTis set in the shell, which overrides thecomacontext.coma connectwarns about both.dockeris an alias for podman, and you connected to a Docker engine. See Podman.- A tool replaced
DOCKER_CONFIG, which also drops thecomacontext. Coding agents do this to work around a missing credential helper.
While you are connected, comad watches the local engines it can find (/var/run/docker.sock, Docker Desktop, a Podman machine, rootless Podman, Colima, OrbStack) and records every container created there. coma doctor reports them in local-fallback, with the latest container's name, image and time; coma daemon logs lists each one.
Fix the cause, then check with docker context show, which should print coma.
coma port list shows each mirrored port. The state local port in use means a program on your computer already listens on that number, and the line below the table names it. A local database, Docker Desktop or a local Podman machine are the usual owners.
Stop the local program, or declare the port in coma.yaml at another local number:
spec:
ports:
- remote: 5432
local: 15432The declared port replaces the mirror of port 5432 while the workspace is up. See the coma.yaml reference.
Docker shows COMA's reason with a code:
sync_bind_source_unmanaged: the path is outside every directory COMA syncs to this machine. Sync a directory that contains it (coma sync watch --path <dir>), or use a workspace.sync_bind_source_missing: the path is ignored by sync but has content on your computer. To sync it, add it tospec.sync.includeincoma.yaml.coma sync explain <path>says which rule ignores it.sync_barrier_timeout: your latest changes were not on the machine in time, so the container was not created. Checkcoma sync status, then retry.
In the default one-way-safe mode, sync never overwrites a file that changed on the machine. A file changed both on your computer and on the machine is a conflict, and the machine's copy is kept. coma sync status counts conflicts and names each file.
Choose which copy wins:
coma sync resolve src/app.py --keep local--keep local copies your version to the machine; --keep machine copies the machine's version to your computer. Files that both a container and a local run write, such as __pycache__/, cause repeated conflicts: add them to .gitignore or .comaignore.
comad notices when your computer wakes up, checks every machine connection at once and reconnects. Port mirrors and sync recover too. You do not need to reconnect.
While a connection is being restored, Docker clients wait up to 10 s, then get an error that names the machine and the reason. After 5 failed attempts in a row the endpoint shows degraded, and COMA keeps retrying. Open connections through a port mirror end when the link drops; new ones work once it is back.
Two failures stop the retries until the next coma connect: a changed host key and a refused SSH login. Check with coma endpoint list and coma daemon logs.
COMA refuses to connect with ssh_host_key_mismatch (exit 5). This happens after a server is reinstalled, and it is also what a man-in-the-middle attack looks like. Check the new fingerprint with the server's owner. Then remove the old entry from COMA's known_hosts file; the error's details name the file and the entries.
You are running Compose v1. coma doctor lists every Compose v1 on PATH in its docker-compose check. Remove the old docker-compose and use docker compose. See Docker Compose.
Docker's config.json names a credential helper that is not installed, for example "credsStore": "osxkeychain" after removing Docker Desktop. coma doctor reports it in docker-credentials. Remove credsStore or credHelpers, or install the helper.
A context called coma exists that COMA did not create (docker_context_conflict). Rename it with docker context, or run coma connect --replace to let COMA manage it.
workspace_plan_blockedwithbidirectional: that sync mode copies changes on the machine back to your computer, socoma.yamlalone cannot turn it on. Setsync.allowBidirectional: truein your COMA config file, orCOMA_SYNC_ALLOW_BIDIRECTIONAL=1.confirmation_required:one-way-mirrordeletes and overwrites files on the machine, so its first sync asks. Re-run with--yes.sync_mode_unsupported: both opt-in modes need the Mutagen sync engine. Checksync-helperincoma doctor.
COMA forwards the interrupt to the machine. A container whose main process ignores it keeps running, as it would on a local engine. COMA says so and exits with 130. Stop the container on the machine, and use docker run --init for commands you may interrupt.
Logs
Every command can log to stderr:
| Flag | Shows |
|---|---|
--verbose | What is happening (info level) |
--debug | Debug logs |
--trace | Trace logs, including timings |
--log-format json | Logs as JSON lines instead of text |
COMA_LOG_LEVEL and COMA_LOG_FORMAT set the same for every command. See Environment variables.
comad, COMA's background process, writes its own log, with a date and time on every line. Print the end of it with:
coma daemon logs --lines 100coma daemon status shows whether comad is running and where the log is:
| Setup | comad log |
|---|---|
| macOS | ~/Library/Logs/coma/comad.log |
| Linux | $XDG_STATE_HOME/coma/logs/comad.log (default ~/.local/state/coma/logs/comad.log) |
COMA_HOME set | $COMA_HOME/logs/comad.log |
coma daemon stop stops comad. Docker commands through COMA then fail until the next coma connect, which starts it again.
If COMA itself hits a bug, it says so and asks you to report it with the output of coma doctor --json. Add --debug to the failing command to include a stack trace.