Troubleshooting
Common issues and fixes for self-hosted Orsa instances.
Browser Pool Won't Start
Symptoms
- Browser worker container exits immediately
- Health check at
/healthreturns connection refused - Logs show
Failed to launch browserorChromium not found
Fixes
Shared memory too small:
# Docker Compose — add shm_size
services:
browser-worker:
shm_size: '512mb' # Must be ≥256 MB
# Kubernetes — mount emptyDir as /dev/shm
volumes:
- name: dshm
emptyDir:
medium: Memory
sizeLimit: 512MiMissing Chromium dependencies (non-Docker):
# Debian/Ubuntu
apt-get install -y libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 \
libcups2 libdrm2 libdbus-1-3 libxkbcommon0 libatspi2.0-0 \
libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 \
libpango-1.0-0 libcairo2 libasound2 fonts-liberation
# Or install all Playwright deps automatically
npx playwright install-deps chromiumPlaywright browsers not installed:
npx playwright install chromiumNot enough memory:
Each Chromium instance needs ~200-400 MB RAM. If BROWSER_POOL_SIZE=3, ensure at least 2 GB available.
# Check container memory
docker stats orsa-browser-worker-1Port conflict:
# Check if port 3002 is in use
lsof -i :3002
# Change the port
docker compose up -d # Uses PORT from environmentProxy Errors
Symptoms
407 Proxy Authentication RequiredECONNREFUSEDto proxy host- Scraping returns blocked/CAPTCHA pages
ProxyError: tunnel connection failed
Fixes
Authentication failure (407):
# Verify proxy URL format — must include credentials
PROXY_DATACENTER_URL=http://USERNAME:PASSWORD@proxy-host:port
# Special characters in password? URL-encode them
# @ → %40, : → %3A, # → %23
PROXY_DATACENTER_URL=http://user:p%40ssw%23rd@proxy-host:portProxy connection refused:
# Test proxy directly
curl -x "http://user:pass@proxy-host:port" https://httpbin.org/ip
# Check if proxy provider IP allowlist is configured
# Many providers require you to whitelist your server's IPGetting blocked despite proxies:
- Upgrade proxy tier (datacenter → residential → ISP)
- Check if the target site requires JavaScript rendering (use the browser worker instead of direct HTTP)
- Reduce request rate to the same domain
- Enable proxy rotation (most providers support this natively)
Disable proxy escalation for debugging:
PROXY_ESCALATION_ENABLED=falseDatabase Connection Issues
Symptoms
ECONNREFUSEDto Supabase URLJWT expiredorInvalid API keyrelation "brands" does not exist- Timeout connecting to database
Fixes
Wrong Supabase URL:
# Local development
NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321 # Not 54323 (that's Studio)
# Cloud
NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co # No trailing slashMigrations not applied:
# Check migration status
supabase migration list
# Apply pending migrations
supabase db push
# Nuclear option — reset and reapply everything
supabase db reset # WARNING: destroys all dataSupabase not running (local):
# Check status
supabase status
# Start/restart
supabase stop
supabase startService role key vs anon key confusion:
NEXT_PUBLIC_SUPABASE_ANON_KEY— Public key, used in browser, respects RLSSUPABASE_SERVICE_ROLE_KEY— Server-side key, bypasses RLS. Never expose to client.
Connection pooling (production): If you're hitting connection limits, enable Supabase connection pooling:
# Use the pooled connection string (port 6543 instead of 5432)
# Supabase Dashboard → Settings → Database → Connection PoolingRequired extensions not enabled:
-- Run in Supabase SQL Editor or via migration
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
CREATE EXTENSION IF NOT EXISTS "pg_trgm";
CREATE EXTENSION IF NOT EXISTS "vector";Rate Limiting Not Working
Symptoms
- All requests succeed regardless of plan limits
- Rate limit headers missing from responses
@upstash/ratelimiterrors in logs
Fixes
Redis not connected:
# Test Redis connection
curl "${UPSTASH_REDIS_REST_URL}/ping" \
-H "Authorization: Bearer ${UPSTASH_REDIS_REST_TOKEN}"
# Must return {"result":"PONG"}Wrong Redis URL format:
# Upstash REST API requires HTTPS URL, not redis:// protocol
# ✅ Correct
UPSTASH_REDIS_REST_URL=https://us1-xxxxx.upstash.io
# ❌ Wrong
UPSTASH_REDIS_REST_URL=redis://us1-xxxxx.upstash.io:6379Self-hosted Redis without REST proxy:
The @upstash/redis SDK requires Upstash's REST API. If using self-hosted Redis, you need the REST proxy:
docker run -d --name redis-rest-proxy \
-p 8079:8079 \
-e REDIS_URL=redis://redis:6379 \
ghcr.io/upstash/upstash-redis-rest-proxy:latest
UPSTASH_REDIS_REST_URL=http://localhost:8079
UPSTASH_REDIS_REST_TOKEN=your-proxy-tokenRate limit key not set:
Ensure API key authentication is working. Rate limits are keyed on the API key — if auth is bypassed, rate limiting won't bind to a specific user.
Cache Misses
Symptoms
- Every request triggers a fresh extraction (slow responses)
cached: falsein every response- Redis shows no keys with
orsa:cache:prefix
Fixes
Redis not connected: Same as rate limiting — verify Redis connectivity first.
Cache TTL set to 0:
# Check your env — a TTL of 0 disables caching for that type
CACHE_TTL_BRAND=604800 # Should be > 0Client bypassing cache:
Check if clients are passing ?cache=false in their requests. This forces a fresh extraction.
Cache key mismatch: The cache key includes a hash of normalized parameters. If the domain normalization changed between versions, old cache entries won't match. Clear the cache:
# Clear all Orsa cache keys in Redis
# Via Upstash REST API:
curl -X POST "${UPSTASH_REDIS_REST_URL}/eval" \
-H "Authorization: Bearer ${UPSTASH_REDIS_REST_TOKEN}" \
-d '["local keys = redis.call(\"keys\", \"orsa:cache:*\"); for i,k in ipairs(keys) do redis.call(\"del\", k) end; return #keys", "0"]'Redis memory full: If Redis runs out of memory, it evicts keys. Check memory usage:
curl "${UPSTASH_REDIS_REST_URL}/info/memory" \
-H "Authorization: Bearer ${UPSTASH_REDIS_REST_TOKEN}"Stripe Webhook Issues
Symptoms
- Subscriptions created but credits not applied
Webhook signature verification failedin logs- Events not reaching your endpoint
Fixes
Wrong webhook secret:
# The webhook secret changes when you recreate the endpoint
# Local dev: stripe listen outputs the secret
stripe listen --forward-to localhost:3001/api/webhooks/stripe
# Look for: whsec_xxxxx
STRIPE_WEBHOOK_SECRET=whsec_xxxxx # Must match exactlyWebhook URL not reachable:
- Ensure your API is publicly accessible at the webhook URL
- Check firewall rules
- Verify the path:
/api/webhooks/stripe(not/api/webhook/stripe)
Missing events: Make sure these events are enabled in the Stripe webhook configuration:
checkout.session.completedcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deletedinvoice.paidinvoice.payment_failed
Build Failures
pnpm install fails
# Clear pnpm cache
pnpm store prune
# Delete node_modules and reinstall
rm -rf node_modules
find . -name "node_modules" -type d -prune -exec rm -rf {} +
pnpm installTypeScript errors after update
# Regenerate database types
pnpm generate:types
# Clear Turbo cache
rm -rf .turbo
pnpm buildDocker build fails for browser worker
# Common: Docker buildx platform mismatch on M1/M2 Mac
docker build --platform linux/amd64 -t orsa-browser-worker ./services/browser-workerLogs
Where to Find Logs
| Component | Location |
|---|---|
| API (dev) | Terminal running pnpm dev |
| API (Vercel) | Vercel Dashboard → Logs |
| Browser Worker (Docker) | docker compose logs browser-worker |
| Browser Worker (Fly.io) | flyctl logs --app orsa-browser-pool |
| Supabase (local) | supabase logs |
| Trigger.dev | Trigger.dev Dashboard → Runs |
Enable Debug Logging
LOG_LEVEL=debug pnpm devBrowser Worker Verbose Logs
# In docker-compose.yml or environment
LOG_LEVEL=debug
DEBUG=pw:browser* # Playwright debug logsGetting Help
- Search existing issues: github.com/paragonhq/orsa/issues (opens in a new tab)
- Open a new issue with:
- Orsa version (
git rev-parse HEAD) - Deployment method (Docker, K8s, Vercel)
- Relevant logs (redact API keys)
- Steps to reproduce
- Orsa version (
- Community discussions: github.com/paragonhq/orsa/discussions (opens in a new tab)