Skip to main content

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.scriptsbackground.service_worker; browser_actionaction; webRequestBlockingdeclarativeNetRequest.


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:

  1. Verify the finding: read the CVE description and confirm whether the affected code path is reachable.
  2. If a true false positive, add an inline suppression with justification:
    // nosec G402 -- TLS min version enforced at the load-balancer layer
  3. Open a tracking issue to revisit when a patched version is available.
  4. 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.