Limits
Ingest
| Limit | Value |
|---|---|
| Total request size | 25 MB |
| Decompressed envelope | 5 MB |
| Attachments per report | 5 |
| Single attachment | 25 MiB — in practice the total cap trips first |
| Rate limit, per SDK key | 60 / minute, when enabled |
| Rate limit, per source IP | 200 / minute, when enabled |
Envelope content
| Field | Cap |
|---|---|
reporter.title | 50 characters |
reporter.description | 600 in the protocol, 400 at ingest |
payload.extra | 2 000 characters |
payload.breadcrumbs | 128 entries |
| Breadcrumb byte budget | 16 KB by default; the server may raise it, up to 64 KB |
| Console entries | 100. console.maxEntries on React and Web changes it; the native ringBufferCapacity field is currently not read. |
| Network entries | 100 (configurable) |
Caps are enforced by truncation at the SDK, not by rejection — a report that
would exceed a cap ships trimmed, with a trim marker in the breadcrumb chain,
rather than failing. payload.extra is truncated silently at the setExtra
call site.
reporter.description is the one to know about. The protocol allows 600
characters and ingest clips to 400, so a description between the two is
accepted and arrives 200 characters shorter than the user typed. Cap your own
input at 400 if you surface a counter.
Typical sizes
A median envelope is about 84 KB, mostly the screenshot. Console and network entries are deltas from a rolling buffer and the breadcrumb chain is capped, so size scales with the screenshot far more than with session length.
Error codes
Ingest
| Status | Error | Retry? | What to do |
|---|---|---|---|
400 | schema_validation_failed | no | The envelope did not match the schema, or carried an unknown top-level key. details lists the failing paths. |
400 | envelope_too_large | no | The decompressed envelope exceeded 5 MB. 400, not 413. |
400 | attachment_missing | no | The envelope names a partName that was not uploaded. |
400 | attachment_unexpected | no | A part was uploaded that the envelope does not reference. |
400 | envelope_part_missing | no | No envelope part in the multipart body. |
400 | envelope_invalid_json | no | The envelope part was not valid JSON, or could not be gunzipped. |
400 | no_parts | no | The request carried no parts at all. |
400 | sha256_mismatch / bytelength_mismatch | no | A part did not match the hash or length declared for it. |
400 | attachment_sha256_mismatch | no | An attachment’s bytes did not hash to its declared sha256. |
413 | attachment_too_large | no | One attachment exceeded 25 MiB. |
401 | invalid_sdk_key | no | Check the key and that the app still exists. |
403 | org_suspended | no | Ingestion is suspended: the organisation exceeded its plan’s monthly active install limit for two complete months and is over again. Upgrade, or finish a month within the limit. The body carries reason (over_allowance) and since (a date). Rejected reports are not stored. |
413 | payload_too_large | no | The whole request exceeded 25 MB. Drop or downscale the screenshot. |
429 | rate_limit_exceeded | yes | Back off; honour Retry-After. |
Ticket API
See Ticket API for its own codes — it uses a different credential and a different error vocabulary.
SDK errors
Capture failures never become your crash: the SDKs swallow internal errors rather than propagating them out of a capture path.
That is not the same as “nothing throws”. iOS start(config:) is throws and
report.open() is async throws, and Android’s start validates its config —
those are public calls that report a problem to you deliberately, and you should
handle them.
On React you can see those failures, via onError and debug:
<TraceItXProvider config={{
apiKey: 'txx_live_…',
debug: true,
onError: (err) => console.warn('[traceitx]', err.name, err.message),
}}>
Both exist on React and Web only. The native and React Native SDKs expose
neither: on iOS and Android, captureGate and currentConfig show what the SDK
thinks its state is; otherwise read the platform log.
If reports are not arriving, the usual causes are a wrong key, a provider or
start() call that does not run on the path you think it does, and — on the
web — a strict CSP with no cspNonce. See your SDK’s Configuration page.