Troubleshooting
Observable checks to run against your own instance when something isn't working.
TabSlate Server doesn't expose a /health endpoint in the open-source build — there's nothing to curl for a quick yes/no. The checks below all rely on what you can already observe from the container, its logs, and your own configuration.
Is the stack running at all
docker compose psBoth api and caddy should show as running. If api keeps restarting, its logs are the next stop:
docker compose logs apiThe server fatals (and the container exits) at startup if DATABASE_URL or JWT_SECRET is missing, if the database connection or ping fails, if the embedded migration fails, or if REDIS_URL is set but doesn't parse as a valid Redis URL — the log line right before the container exits names which one.
Database reachability
Confirm DATABASE_URL actually starts with postgres:// or postgresql:// — any other scheme is rejected before the server even tries to connect. If the scheme is right but the server still can't reach it, check that the host/port are reachable from inside the container's network (not just from your own machine), and that credentials and database name are correct.
JWT secret present
If api exits immediately with a log line about a missing required environment variable, check that JWT_SECRET (and DATABASE_URL) are actually set in .env and that docker-compose.yml's env_file: .env is pointed at the file you edited.
Behind a reverse proxy
If you're not using the bundled Caddy service and put your own reverse proxy in front of api, make sure its address is covered by TRUSTED_PROXIES (RFC1918 ranges are trusted by default, which covers most Docker/Traefik setups) — otherwise client-IP-based rate limiting sees the proxy's address instead of the real client's for every request.
Email not sending
If verification or password-reset emails never arrive, check whether MAIL_PROVIDER is set at all — leaving it empty is a valid configuration, but it means every new registration is auto-verified and no OTP is ever sent, silently. If it is set, confirm the matching provider credentials for that provider (SMTP_*, RESEND_API_KEY, or SES_*) are present in .env.
Search always empty
If GET /search never returns anything, check whether MEILISEARCH_HOST is set — without it, search indexing is disabled and the endpoint always returns an empty result list rather than an error, so there's no failure to see in the logs.
Redis-dependent behavior
If real-time sync doesn't propagate between multiple server instances, or rate-limit/captcha-threshold counters reset unexpectedly, confirm REDIS_URL is set and parses correctly — the server logs which mode it started in (infra: using Redis providers (...) or infra: using in-memory providers (OSS mode)) right at startup.
Extension can't connect
- Confirm the server URL entered in the extension (see Connect the Extension) is the exact HTTPS origin your reverse proxy serves — not
http://, and not a URL still pointing at the default TabSlate Cloud address. - Check the browser's network tab for the actual failing request: a TLS error means the certificate isn't trusted by the browser (see Connect the Extension); a CORS error means the request reached the server but was rejected before it — the server only allows browser-extension origins (
chrome-extension://,moz-extension://) and empty/nullorigins, so a request coming from anywhere else (like a browser tab hitting the API directly) will be blocked as expected.
Last updated on