Troubleshooting
Common symptoms when running stylobot, and the fix.
Stylobot won't start
| Symptom |
Fix |
Address already in use on the listen port |
sudo lsof -i :5080 (or your port). Pick a free port or kill what's using it. |
FATAL: --enable-api requires at least one entry under BotDetection:ApiKeys |
Add a key entry under BotDetection:ApiKeys in appsettings.json and restart. Generate the value with stylobot genkey. |
Could not parse certificate with --cert/--key |
The PEM files must be readable by the user running stylobot, both cert and key paths must resolve, and the key must match the cert. Try openssl x509 -in cert.pem -noout -text to confirm the cert parses standalone. |
| Stylobot exits immediately with no error |
Run with --mode demo and Logging__LogLevel__Default=Debug to surface the startup error. The default logger writes to logs/stylobot-*.log next to the binary. |
Requests not reaching the upstream
| Symptom |
Fix |
/_stylobot/ returns 404 |
You're hitting the upstream, not Stylobot. Confirm the URL matches Stylobot's listen port, not the upstream's. |
| All requests return 502 / 504 |
Upstream is unreachable from the gateway process. curl -is http://localhost:3000/ (or wherever your upstream is) from the same host. Check firewall rules between the gateway host and the upstream. |
| Cloudflare 502 with origin healthy |
Stylobot is up, but the WebSocket path (for SignalR dashboard) is blocked. Confirm the path through Cloudflare allows Upgrade: websocket. |
Dashboard problems
| Symptom |
Fix |
| Fingerprint radar shows "Calibrating fingerprint" forever |
Set BotDetection__Identity__Enabled=true. Without the identity matcher running, no fingerprint binding gets written and the radar has nothing to render. |
| Top Bots / Visitors lists are empty but Live Activity is filling |
The dashboard caches are remote-mode and haven't been warmed yet. Hit any signature detail URL to trigger backfill, or wait one read-cycle. |
| Signature names show as "Unknown Bot" or "New Fingerprint - ..." |
The name composer needs an archetype match. Either the visitor hasn't accumulated enough requests yet (need ~5+), or no archetype YAML covers the visitor's shape. Add archetypes under BotDetection:Identity:Archetypes. |
| Live Activity feed shows nothing |
Confirm SignalR isn't being blocked. In the browser devtools Network tab, the /_stylobot/dashboardHub WebSocket should be open. If it returns 404, your reverse proxy isn't forwarding Upgrade: websocket. |
Verdict / scoring issues
| Symptom |
Fix |
Every verdict shows 0% bot probability for humans |
You're on a pre-7.0 build that lacked the NonAiMinProbability floor. Upgrade to 7.0+ or set BotDetection__NonAiMinProbability=0.01 explicitly. |
| Verdict on a specific signature looks wrong |
Click "Flag as wrong" on the Your Detection card on the dashboard. Stylobot logs the click + fingerprint id for offline review. For ongoing analysis, enable BotDetection:Debug:BdfHarvest:Enabled=true to capture the full bot-detection-frame for that signature. |
| Same visitor classifies differently every restart |
Set BotDetection__SignatureHashKey to a stable base64 value (stylobot genkey produces one). Without it, the gateway uses a session-scoped random key and warns at startup, so signature hashes rotate every run. |
| Self-declared Googlebot is being blocked |
Either enable verified-bot policy (AllowVerifiedBots: true in your action policy), or check that Stylobot has reachable DNS to verify the Google IP range. Without verification, a self-declared Googlebot from a non-Google IP is correctly flagged as spoofed. |
LLM not firing
| Symptom |
Fix |
| Fingerprints never get named by the LLM |
Both BotDetection__AiDetection__Provider=ollama (or your provider) AND BotDetection__EnableLlmDescriptions=true need to be set. The first wires the provider; the second turns on the background description coordinator. |
| Ollama provider configured but no requests reach Ollama |
Confirm the endpoint and model are reachable: curl http://<host>:11434/api/tags should list your model. Stylobot calls the OpenAI-compatible /v1/chat/completions route on the Ollama endpoint, so the model must support chat. |
| LLM calls timeout under load |
Lower BotDetection:AiDetection:MaxConcurrentRequests (default 2). The LLM is best-effort: timeouts degrade fingerprint quality but never block requests. |
| Symptom |
Fix |
| Memory creeps over hours |
Pick a tighter Kestrel profile (STYLOBOT_PROFILE=api or highrisk), or wipe sessions.db between runs with stylobot clear --sessions. |
| Tail latency spikes on cold IPs |
Synchronous IP enrichment (Cymru ASN DNS, ip-api geo) blocks the first request per cold IP for ~20s. Disable with BotDetection:Enrichment:Cymru:Enabled=false and BotDetection:Enrichment:IpApi:Enabled=false, or pre-warm with a threat-feed prefetch. |
| Stylobot consuming >5% of upstream CPU budget |
Switch to --profile api (no WebSocket overhead) or --profile highrisk (small body cap, fast reject). The "Processing Time History" widget on the dashboard shows the actual share. |
Safe rollout checklist
When you're ready to enforce, walk through this in order:
- Start with
--mode demo --policy allow. Watch the dashboard for 24 hours. Read what gets flagged.
- Confirm no real users are appearing in the Bots tab.
- Flip to
--mode production --policy throttle-stealth. Low blast radius: bots experience a slow site; humans don't notice.
- After another 24h, tighten to
--policy block for paths where false-positive cost is low (/.env, /wp-login.php, /admin/*).
- Set
BotDetection__SignatureHashKey to a stable base64 value so signatures persist across restarts.
- Set
BotDetection__Identity__Enabled=true so the matcher writes fingerprint rows and the dashboard radar renders.
Still stuck