Troubleshooting
Symptom → cause → fix for the most common issues across every layer of the Noxys dev stack.
Local Environment
Docker not starting
Symptom: docker compose up exits immediately or containers crash-loop.
Cause: Docker daemon not running, or a previous run left stale lock files.
Fix:
# Verify daemon is up
docker info
# Remove stale containers and volumes, then restart
docker compose down -v
docker compose up --build
DB connection refused (dial tcp 127.0.0.1:5432: connect: connection refused)
Symptom: API logs show Postgres connection error on startup.
Cause: The postgres container is not healthy yet, or the port mapping is missing.
Fix:
# Check container health
docker compose ps
# Wait for healthy state, then restart the api container
docker compose restart api
Ensure POSTGRES_HOST=postgres (service name) not localhost when running inside Compose.
NATS not reachable (nats: no servers available for connection)
Symptom: API panics or logs NATS connection error at boot.
Cause: NATS container not started, or NATS_URL points to wrong host.
Fix:
docker compose up nats -d
# Verify
docker compose logs nats | tail -20
Set NATS_URL=nats://nats:4222 inside Compose; nats://localhost:4222 for local binary runs.
Port conflict (bind: address already in use)
Symptom: Container or dev server fails to bind to its port.
Cause: Another process occupies the port.
Fix:
# Find the culprit (replace 8080 with the conflicting port)
lsof -i :8080
kill -9 <PID>
# Or remap in docker-compose.override.yml
API (Go)
Build error: cannot find module providing package ...
Symptom: go build ./... fails with missing package.
Cause: Dependency not downloaded, or go.mod out of sync.
Fix:
go mod tidy
go mod download
go build ./...
Migration failure (pq: relation "..." does not exist or dirty database)
Symptom: API exits on startup with migration error.
Cause: A previous migration run was interrupted and left the DB in a dirty state.
Fix:
# Force-set the version to the last clean migration (replace N)
migrate -database "$DATABASE_URL" -path db/migrations force N
# Re-run
migrate -database "$DATABASE_URL" -path db/migrations up
Test failure with -race detector (DATA RACE)
Symptom: go test -race ./... reports a data race.
Cause: Shared mutable state accessed from multiple goroutines without synchronization.
Fix: Locate the two conflicting goroutines in the race output. Add a sync.Mutex or use channels. Never suppress the race detector — fix the root cause.
Panic: JWT_SECRET is not set
Symptom: API panics at startup with missing env var.
Cause: .env file not loaded or env var not exported.
Fix:
# Copy the example and fill values
cp .env.example .env
export $(grep -v '^#' .env | xargs)
Required vars: JWT_SECRET, DATABASE_URL, NATS_URL, INFISICAL_TOKEN (or equivalent).
Missing env var at runtime
Symptom: Unexpected nil pointer / empty string causing a panic deep in the call stack.
Cause: config.Load() doesn't validate all required keys.
Fix: Add a mustGet(key string) guard in internal/config/config.go that panics with a clear message if the var is absent. Validate at startup, not at first use.
Console (React / Vite)
pnpm install fails (EACCES or peer dep conflict)
Symptom: Install exits with permission error or unresolvable peer deps.
Fix:
# Permission error — fix ownership
sudo chown -R $(whoami) ~/.local/share/pnpm
# Peer dep conflict — use --legacy-peer-deps equivalent
pnpm install --shamefully-hoist
HMR not working (page not reloading on save)
Symptom: Vite dev server runs but changes don't trigger a hot reload.
Cause: File watcher using inotify exhausted, or polling not enabled in a VM/WSL2.
Fix:
# In .env.local
VITE_FORCE_POLLING=true
Or set server.watch.usePolling: true in vite.config.ts.
CORS error against API (Access-Control-Allow-Origin missing)
Symptom: Browser console shows CORS blocked on api.noxys.cloud or localhost:8080.
Cause: API CORS_ORIGINS env var doesn't include the console origin, or the proxy in vite.config.ts is not configured.
Fix (local):
// vite.config.ts
server: {
proxy: {
'/api': 'http://localhost:8080',
},
}
Fix (staging/prod): Add the console origin to CORS_ORIGINS in the API environment.
Extension (Chrome / Firefox)
Manifest version warning / rejection
Symptom: Chrome flags the extension with "Manifest version 2 is deprecated."
Cause: manifest.json still declares "manifest_version": 2.
Fix: Migrate to Manifest V3. Key changes: background.scripts → background.service_worker; browser_action → action; webRequestBlocking → declarativeNetRequest.
Service worker not loading (Service worker registration failed)
Symptom: Background script never runs; no events received.
Cause: Syntax error in the service worker file, or a non-ES-module import in an MV3 service worker.
Fix:
# Check for syntax errors
node --check src/background/service-worker.ts
# Reload extension after fix
# chrome://extensions → Developer mode → Reload button
Content script not injected
Symptom: The extension does nothing on matching pages; no console output.
Cause: matches pattern in manifest.json doesn't cover the target URL, or run_at timing is wrong.
Fix: Verify content_scripts[].matches includes the URL (e.g., "https://*/*"). Use "run_at": "document_idle" for most cases; switch to "document_start" only if you need to intercept early page events.
Infrastructure
SSH to VPS failing (Connection refused or Permission denied)
Symptom: ssh deploy@<VPS_IP> fails.
Fix:
# Test connectivity
ping <VPS_IP>
# Check key is loaded
ssh-add -l
# Verbose connect
ssh -v deploy@<VPS_IP>
Ensure your public key is in ~/.ssh/authorized_keys on the VPS and sshd is running (systemctl status sshd).
Docker container unhealthy
Symptom: docker compose ps shows (unhealthy).
Fix:
# Read the health check output
docker inspect --format='{{json .State.Health}}' <container_name> | python3 -m json.tool
# Tail logs
docker compose logs --tail=50 <service>
Fix the underlying service error shown in the logs, then docker compose restart <service>.
Infisical secrets not loading
Symptom: API starts but all secret values are empty; INFISICAL_TOKEN is set.
Cause: Token expired, wrong environment (dev vs staging), or INFISICAL_PROJECT_ID mismatch.
Fix:
# Verify token is valid
infisical secrets --env=dev --projectId=$INFISICAL_PROJECT_ID
# Re-authenticate if expired
infisical login
infisical export --env=dev > .env
CI/CD
GitHub Actions job failing: permission denied on script
Symptom: chmod +x or script execution fails in the workflow.
Fix: Commit the script with execute bit:
git add --chmod=+x scripts/deploy.sh
git commit -m "chore: fix execute permission on deploy script"
Security scan false positive (Trivy / Semgrep)
Symptom: CI blocks on a vulnerability that is not exploitable in context.
Fix:
- Verify the finding: read the CVE description and confirm whether the affected code path is reachable.
- If a true false positive, add an inline suppression with justification:
// nosec G402 -- TLS min version enforced at the load-balancer layer - Open a tracking issue to revisit when a patched version is available.
- Never suppress a finding without a documented reason.
Deploy not triggering after push
Symptom: Push to main (or staging) succeeds but the workflow does not start.
Cause: Branch protection rule mismatch, workflow file not on the target branch, or the on.push.branches filter is wrong.
Fix:
# Check workflow triggers
cat .github/workflows/deploy.yml | grep -A5 "^on:"
# Verify the branch name matches exactly
git branch --show-current
Also check Actions → Settings → "Allow all actions" is enabled and the workflow is not disabled.