Errors
Ingest error codes with what to do next: body limits, spike valve, and rate caps.
Ingest and most API failures return JSON:
{ "error": "invalid_dsn", "message": "DSN authentication failed" }Error response shape
The dashboard session gate returns { "error": "unauthenticated" } with no message. Login and register rate limits return plain text 429.
Ingest error codes
| HTTP | error | What happened | What to do |
|---|---|---|---|
400 | invalid_envelope | Malformed envelope, or no event item | Use a fixture from fixtures/sentry/ or an official SDK |
400 | invalid_store | Empty, invalid JSON, or decompress failure | Send JSON or gzip/zlib with Content-Encoding |
400 | invalid_release_version | Version contains .., /, or \ | Use a path segment like 1.0.0 |
400 | invalid_release_file | Missing file or path escape | Multipart field file; see Source maps |
401 | invalid_dsn | Missing/invalid DSN credentials | Copy key from Settings → SDK connection |
403 | dsn_revoked | Key revoked | Create or rotate; update dsn |
403 | project_mismatch | Key does not belong to {project_id} | URL project id must match the DSN |
403 | ingest_cap_exceeded | Hourly project cap hit | Wait or raise cap in project settings |
404 | event_not_found | User-feedback event_id unknown | Ingest the event first |
413 | payload_too_large | Body over 2 MB | Shrink envelope/store body |
500 | storage_error | Persist / DSN lookup / artifact write | docker compose logs epure; artifacts volume |
503 | queue_unavailable | Ingest mpsc channel closed | Restart epure |
Body size: ingest router applies RequestBodyLimitLayer at 2 × 1024 × 1024 bytes.
Rate limits and valves
| Mechanism | Default | Effect |
|---|---|---|
| Spike valve | 100 raw events / minute / fingerprint | Still 202; excess bodies not stored; issue counter increments |
| Project ingest cap | 5000 events / hour / project | 403 ingest_cap_exceeded |
| Login / register | 20 requests / IP / 60 s | 429 plain text |
Spike saturation returns 202 Accepted, so clients see no error. Operators see elevated event_count without proportional stored event rows.
Ingest cap is checked before enqueue. Cap hits may also emit an internal alert (kind: ingest_cap_hit) for the dashboard Alerts rail.
There is no Redis-backed global rate limiter. Valves are in-process on the Rust binary.
Dashboard status codes
| HTTP | Typical cause | What to do |
|---|---|---|
400 | Invalid body (status, snooze mode, empty merge list, >200 trend IDs) | Match the schema on Issues |
401 | Missing/invalid session | Login again; check cookie Secure flag |
404 | Issue / project not in session org | Wrong org or deleted row |
500 | Storage / unexpected server error | docker compose logs epure |
Do ingest errors include CORS headers?
Successful ingest responses attach CORS headers when the request Origin is allowed. Error helpers that return early may omit CORS, so browser SDKs should treat any non-2xx as a failure.
202 but Issues still empty?
Not an error code. Accept is non-blocking, so persist may still be in the Tokio queue. Match the environment chip to the SDK tag, confirm the project that owns the DSN, then read docker compose logs epure. Verify lists the same matrix.
Why is there no Redis rate limiter?
The stack is two containers: Rust binary plus PostgreSQL 16. The token bucket and hourly counter live in-process. A saturated spike valve still returns 202, and the hourly cap returns 403 ingest_cap_exceeded. See Configuration.
What is the 2 MB cap?
The ingest router applies RequestBodyLimitLayer at 2 × 1024 × 1024 bytes, and anything larger returns 413 payload_too_large. Shrink the envelope or store body. Release file uploads share the same cap. This is separate from the spike valve, which still returns 202.
What does the spike valve do?
Default 100 raw events per minute per fingerprint, and clients still receive 202. Excess bodies are not stored while the issue counter increments. Operators then see elevated event_count without proportional stored rows, which is expected under a tight loop. The hourly project cap is the 403 path.