Skip to content

Troubleshooting

Who this is for: hosters (sysadmins).

This page is for admins operating the stack. Start from the symptom and work down: the capture page's own error or status message, then the service state, then the logs. If a term here is unfamiliar, check the Glossary. Both supported ways to run the stack are covered: Docker Compose and Co-op Cloud.

The two commands you will reach for most, for the Docker Compose path:

This lists every service and whether it is healthy.

docker compose --env-file .env.production \
  -f docker-compose.yml -f docker-compose.prod.yml ps

This shows the last 100 log lines for all services.

docker compose --env-file .env.production \
  -f docker-compose.yml -f docker-compose.prod.yml logs --tail=100

On Co-op Cloud, use abra app <domain> logs for logs; the caption-ninja recipe documents its status and restart commands.

Symptom, cause and fix

Symptom Likely cause Fix
Speech service returns 400 Bad Request The whisper-host middleware is missing from the caption-local router Restore the middleware that rewrites the backend Host header to 127.0.0.1:8765. Removing it makes the service reject public requests.
Speech service returns 401 Unauthorized No service access token was sent Send Authorization: Bearer <CAPTION_API_KEY>. If you do not have it, ask the service operator; it is not an OpenAI, Google or Gemini key. The browser forgets it on reload.
Relay logs "Relay startup failed" The relay private JSON is missing, or is not readable by uid/gid 1000 Regenerate it, then apply chown 1000:1000 and chmod 600. On Co-op Cloud, re-run the recipe so it recreates the file.
Overlay shows nothing; capture relay stuck reconnecting; publisher gets HTTP 403 The capture page's origin is missing from the relay's origins list Add the exact origin (scheme included, no trailing slash) and recreate the relay. The capture page and the overlays are usually different origins.
Let's Encrypt rate-limited Too many certificate requests Delete the letsencrypt volume and retry after an hour.
Build fails: no submodule content Submodules were never initialised git submodule update --init --recursive.
Ports 80/443 already in use (production) Something else holds the port Free the ports or change the mappings in docker-compose.yml.
Basic Auth prompt never appears The auth overlay was not applied, or the htpasswd file is missing Add -f docker-compose.auth.yml and generate the htpasswd file.
Page unavailable during startup The model is still downloading or warming up Wait and watch the logs for a real error before restarting. A first download can take several minutes.
Offline startup fails The selected model was never cached Cache it while online first: run once while online so the model volume is populated, then enable offline mode.
Microphone is unavailable Browser permission missing, wrong device, or an insecure context Allow the microphone and select the right device. Open the page over localhost or HTTPS; a plain-HTTP remote IP is not a secure microphone context.
Buffer keeps growing, or capture stopped The host cannot keep up with the streams or model Reduce active streams or translation work and competing CPU load. Do not enlarge the buffer to hide a machine that cannot keep up; retry retained audio once fixed.
Relay is disconnected Connectivity issue, or the wrong source room Local captioning still works. Check connectivity and the editor's source room; the relay queue is bounded, so watch its dropped count. External delivery is not guaranteed.
Server restarted on its own A worker exceeded the 90-second watchdog deadline Wait for readiness and retry pending browser audio. The server's retry cache does not survive a restart.
CUDA is unavailable Driver or runtime not present Run nvidia-smi, then test real inference. GPU acceleration intentionally fails when CUDA is requested but unavailable; run the CPU setup instead if needed.
Stream capacity reached The session limit was hit Stop and drain an unused capture page. Abandoned idle sessions expire after 120 seconds. Each producer needs a different stream ID.

Check service health directly

When the stack looks unhealthy, query the speech service's own health endpoint. It reports the model, the actual device, readiness, workers, running and queued requests, and failures.

curl -H "Authorization: Bearer <CAPTION_API_KEY>" http://127.0.0.1:8765/health

Under Docker the port is bound to loopback, so run this on the host itself. On Co-op Cloud, check the app's status through abra instead of calling the port directly.

Fix a relay that rejects your origin

The relay refuses any WebSocket upgrade whose browser origin is not listed. The capture page and the overlays/editor are different origins, so list every one. After editing the private configuration, recreate the relay so it reloads the file:

docker compose --env-file .env.production \
  -f docker-compose.yml -f docker-compose.prod.yml up -d --force-recreate captionninja-relay

On Co-op Cloud, restart the app through the recipe so it reloads the configuration. The relay settings are described in Relay and rooms and Configuration.

Recover from an unexpected restart

The runtime restarts a worker that exceeded its 90-second watchdog deadline, and restart: unless-stopped brings services back; on Co-op Cloud the recipe manages the restart policy. After a restart, wait for readiness and retry pending browser audio; the in-memory retry cache is gone. If restarts are frequent, reduce the model cost or the stream count rather than raising buffers.

Reporting a reproducible issue

Include your OS, release, install method, model, worker/thread/beam settings, number of streams, chosen mode, the exact error, and whether one stream also fails. Attach sanitised /health output and relevant logs. Share audio only if you have permission to publish it, and never include credentials, private room names or confidential transcripts.