Common Errors

Error codes, their causes, and how to fix them.

This page documents the most common error responses from the KubeWatch API and how to resolve them.

HTTP error reference

Error messageHTTP statusCauseFix
unauthorized401Missing Authorization header or X-API-Key, expired JWT, or revoked API keyRe-authenticate to get a new JWT, or check your API key in Settings → API Keys
invalid token401JWT is malformed, has an invalid signature, or has expiredRe-authenticate. If the error persists, verify JWT_SECRET is consistent across services (self-hosted)
missing org_id claim401JWT was issued without an org_id claim (corrupted or from an old version)Re-authenticate. Contact support if this persists after re-login
org_suspended402Your organization's billing is suspended (failed payment)Update your payment method in Settings → Billing
rate_limit_exceeded429Too many API requests per second for your planReduce request rate, add backoff/retry logic, or upgrade your plan
upstream unavailable502A backend microservice is down or unreachableCheck the gateway's /health endpoint, or self-hosted users can check docker compose ps
{"error":"unauthorized"} (from agent, on push)401The agent's session token is invalid, most often because the agent was deleted/removed in the dashboard, or a stale agent process is still pushing with a token from before it re-registeredDelete the stale agent entry if one exists, then restart the agent so it registers fresh
{"error":"invalid api key"} (from agent, on registration)401KUBEWATCH_API_KEY on the agent doesn't match a real key for this orgRegenerate the key in Settings → API Keys and update KUBEWATCH_API_KEY on the agent
org not found404The organization associated with your session no longer existsThe organization may have been deleted, contact support
agent_limit_reached402You've hit the maximum agent count for your planDelete unused agents or upgrade your plan

Self-hosted specific errors

SymptomCauseFix
All services return 502Gateway can't reach backend servicesRun docker compose ps and check which services are Up vs Exit
Login fails with 500Auth service can't reach the databaseCheck docker compose logs auth for DB connection errors and verify DATABASE_URL in .env
Metrics not savingIngestion service crashedCheck docker compose logs ingestion, often a DB schema migration issue on first startup
Dashboard shows blank pageNEXT_PUBLIC_API_URL points to wrong addressUpdate .env and restart the dashboard service
TLS certificate errorsLet's Encrypt cert not issued or expiredCheck docker compose logs caddy and verify DNS points to your server
gateway and auth restart in a loop, whole app unreachableJWT_SECRET is missing from .env, so the services refuse to startSet JWT_SECRET and restart (see Services keep restarting below)
Workloads, Config, RBAC, CRDs, or Approvals pages return 500 or say no dataThe local migrations bundle is stale (it's only downloaded once, at install time)Click Update Now in Settings → System Update, or refresh it manually, see Upgrading

Services keep restarting: JWT_SECRET is required

After an upgrade or a redeploy, the dashboard is unreachable, login fails, and the backend never comes up. docker compose ps shows gateway and auth continuously restarting (on Kubernetes the gateway and auth pods show CrashLoopBackOff).

Check the logs:

cd ~/kubewatch-erp
docker compose logs auth gateway | tail -20

If you see this line, the sign-in secret is missing:

JWT_SECRET is required but not set. Refusing to start with a default secret.

KubeWatch signs every login session with JWT_SECRET. When it is absent the services refuse to start on purpose, rather than fall back to a shared, guessable secret that would let anyone forge a valid session. This is expected safety behavior, not a bug. Every normal install already sets JWT_SECRET (the installer generates one), so you only hit this if the value went missing, usually a .env that was not restored after rebuilding a host.

Fix on Docker Compose

  1. Check whether the value is present:
grep '^JWT_SECRET=' ~/kubewatch-erp/.env
  1. If you have a backup of .env, restore the original JWT_SECRET from it. Reusing the original value keeps everyone's existing sessions valid.

  2. If the original is truly lost, generate a new one:

cd ~/kubewatch-erp
echo "JWT_SECRET=$(openssl rand -hex 32)" >> .env

A new secret is fine, it only signs out anyone currently logged in, who can log back in normally.

  1. Restart the stack:
docker compose up -d

Fix on Kubernetes (Helm)

Set global.jwtSecret in your values (or the Secret it references) and apply it:

helm upgrade kubewatch ./kubewatch-erp \
  --reuse-values \
  --set global.jwtSecret="$(openssl rand -hex 32)"

The gateway and auth pods roll and leave CrashLoopBackOff once the value is set.

Do not change `JWT_SECRET` when it is already working: a new value signs out every active session. And never change `DB_PASSWORD` on an existing install, PostgreSQL keeps the password from when its data volume was first created, so a new value locks every service out of the database. Back up your `.env` so you can always restore the exact values. See [Backup and Restore](/self-hosted/backup-restore).

Agent errors

Log messageCauseFix
failed to connect: dial tcp: connection refusedGateway URL is wrong or gateway is downVerify KUBEWATCH_SERVER_URL and check gateway health
permission denied: /var/run/docker.sockAgent doesn't have Docker socket accessMount the socket and ensure correct permissions (see No Metrics Showing)
push failed: 429 Too Many RequestsPushing too frequentlyIncrease KUBEWATCH_INTERVAL (default is 15s, try 30s)
certificate signed by unknown authoritySelf-hosted with self-signed certInstall a valid TLS certificate on your gateway (self-signed certificates are not supported)
agent_limit_reachedOrganization at agent limitDelete unused agents from the dashboard or upgrade the plan

Getting more help

If you can't find the answer here, email [email protected].

When contacting support, include:

  • Your agent version (docker inspect kubewatch-agent | grep Image)
  • Relevant log output
  • The full error message including HTTP status code