Troubleshooting
Organized by what you see, with the most likely cause first. API error shapes are documented exhaustively in Errors and limits; this page is the triage view.
API: authentication
| Symptom | Likely cause | Fix |
|---|---|---|
401 {"error": "auth_failed"} | Wrong key, or right key on the wrong environment (keys never cross environments) | Verify the key against the environment you are calling; prefixes (cos_live_, cos_dev_, cos_sbx_) identify the environment at a glance |
401 from the fleet agent while the same key works in curl | Older agent builds send Authorization: Bearer; the platform only accepts x-api-key | Check which header your agent version sends; see the integration bundle caveat |
401 with a console-generated key | Keys generated in the console browser are not registered until the platform team provisions them | Get the key provisioned; see Authentication |
429 {"error": "auth_lockout", "retry_after_seconds": N} | 5 auth failures from your IP within 300 seconds; lockout lasts 900 seconds and fires before key verification | Stop the failing client, fix the credential, wait out Retry-After; make clients treat 401 as fatal so this cannot recur |
API: limits
| Symptom | Likely cause | Fix |
|---|---|---|
429 {"error": "rate_limited", "retry_after_seconds": N} | Over 30 requests/min per IP, 60/min per tenant, or the 10/s burst | Honor Retry-After; batch reads (one topology call, up to 100 link_ids per predictions call) instead of per-entity requests |
413 {"error": "request_too_large", ...} | Body over the 1 MB cap | Split the payload; the body names max_bytes and received_bytes |
413 {"error": "batch_too_large", "max": 1000, ...} | More than 1,000 telemetry records in one batch | Chunk to 1,000; never retry the oversized batch as-is |
411 {"error": "length_required"} | Body request without Content-Length (usually chunked encoding) | Send a Content-Length header |
422 with a detail list | A record failed schema validation (bad time format is the classic) | The detail entries locate the failing record by index and field |
API: availability
| Symptom | Likely cause | Fix |
|---|---|---|
503 {"error": "telemetry_unavailable", "upstream": "influx", ...} | Your tenant's data plane is transiently unreachable | Retry after the Retry-After hint (typically 5 seconds) with a retry cap; check GET /health/telemetry |
503 {"error": "tenant_unavailable"} | Key authenticated but the tenant is not registered in this environment | You are probably on the wrong environment for this tenant; otherwise contact the platform team |
403 {"error": "tenant_disabled"} | The tenant has been disabled; fail-closed is intentional | Contact the platform team |
API: empty or odd data
| Symptom | Likely cause | Fix |
|---|---|---|
GET /topology returns 200 with empty entities | No telemetry inside the freshness_seconds window at as_of_utc (default now), or the wrong measurement family | Widen freshness_seconds, pass an explicit as_of_utc for seeded or historical data, confirm the measurement; the key is fine, 200 proves it |
400 {"error": "invalid_input", "field": "entity_type"} | measurement not one of link, satellite, ground_station, weather, telemetry | Custom metrics are written under telemetry with identifying tags; read them back that way |
Predictions return an empty items list | No cached prediction set for those links yet, or link_ids do not match your topology's link identities | Try live=true; cross-check ids against GET /topology?measurement=link |
400 {"error": "too_many_link_ids", "max": 100, ...} | Over the 100-link cap on GET /predictions | Chunk the fleet into requests of 100 |
Console
| Symptom | Likely cause | Fix |
|---|---|---|
| Blank globe, healthy UI | Empty base state (no dataset activated) or every asset group toggled off | Load the demo or a dataset from fleet setup; check group visibility toggles in the Assets panel |
| Satellites frozen or missing after a big timeline seek | The seek landed outside the precomputed propagation window, or assets are outside their TLE epoch validity | Brief coarse motion after a seek resolves itself; persistent absence means stale epochs, check epoch age on the card |
| Chat replies "offline" or only handles simple queries | No chat backend is reachable; the local intent layer still answers deterministic queries | Check connection status under Settings, Chat; verify network access to the chat endpoint |
| Assistant refuses with an upgrade message | Guest query limit (10) exhausted, or the request needs a prediction tier your plan lacks | Sign in or upgrade; see Plans and billing |
| Import rejected records | Malformed TLE lines (wrapping, missing 1 /2 prefixes, NORAD id mismatch across lines) | The per-record report quotes the offending text; fix those records and re-import (dedupe makes this safe) |
| Import succeeded but nothing on the globe | Tabular data without recognizable position columns, or the group is hidden | Check the import warnings; add lat/lon columns or a TLE, check visibility |
| Predictions panel shows "baseline" instead of your model | No tenant API key configured in the console, or guest mode | The baseline is the honest keyless fallback; configure live API access to get your tenant's model |
| Elevation mask or horizon looks synthetic | No terrain token configured | Expected fallback, and labeled as such; real terrain requires a Cesium ion token in the build |
Escalation
If a failure does not match these tables, capture the full response body (the error code is designed to be quoted), the environment, and the UTC time, and check the per-subsystem health endpoints (GET /health/telemetry, /health/topology, /health/predictions) before reporting. Monitor the platform shows how to automate exactly that capture.