Errors
Every error the LinkTrail SDKs report on iOS, Android, React Native and Flutter, what causes each, and the HTTP statuses behind them: 401, 404, 429, 5xx.
All four SDKs report the same eight errors, because the wrappers pass the native ones through. They arrive on onError — and, on the calls that return a result (the async/suspend forms on iOS and Android, the Promises in React Native, the Futures in Flutter), as the thrown or rejected error.
The eight errors
| iOS `LinkTrailError` | Android `LinkTrailError` | React Native `code` | Flutter | Cause and fix |
|---|---|---|---|---|
| .missingAPIKey | MissingApiKey | missing_api_key | LinkTrailMissingApiKeyException | configure got a blank key. Thrown by configure itself (React Native rejects). Pass your lt_live_… key. |
| .invalidAPIKey | InvalidApiKey | invalid_api_key | LinkTrailInvalidApiKeyException | The backend answered 401: the key is wrong or revoked. Arrives on onError, never from configure, and only once the install is sent — after setConsent, or at configure with requireConsent: false. Check Settings → API Keys. |
| .server(statusCode:body:) | Server(statusCode, body) | server | LinkTrailServerException | Any other non-2xx answer, after retries. Read the status code: see the table below. |
| .transport(message:) | Transport(detail) | transport | LinkTrailTransportException | The request never got an answer: offline, a timeout, or a network that blocks https://backend.linktrail.io. Retried before it is reported. |
| .decoding(message:) | Decoding(detail) | decoding | LinkTrailDecodingException | The answer was not the JSON the SDK expected — often a proxy or captive portal answering in its place. |
| .emptyResponse | EmptyResponse | empty_response | LinkTrailEmptyResponseException | The answer had no body where one was expected. Usually the same cause as a decoding error. |
| .notALinkTrailURL | NotALinkTrailUrl | not_a_linktrail_url | LinkTrailNotALinkTrailUrlException | handleDeepLink was given a URL that is not a LinkTrail link. Not a fault — route it yourself. (The plain iOS and Android forms return false instead; React Native resolves null.) |
| .invalidURL(_:) | InvalidUrl(url) | invalid_url | LinkTrailInvalidUrlException | The SDK could not build a request URL. Not expected in normal use — report it on the SDK's issue tracker. |
The wrappers add one each: React Native's not_configured (a call made before configure finished) and unknown, and Flutter's LinkTrailUnknownException for a native code it does not recognise.
HTTP statuses
The SDKs call https://backend.linktrail.io. Its errors are JSON of the shape { "code": …, "message": … } — except the per-IP 429, whose body is the plain text Too many requests, please try again later.
| Status | Means | What the SDK does |
|---|---|---|
| 401 | The API key is wrong, revoked or missing: {"code":401,"message":"Invalid or missing API key"} | Not retried. Reported as the invalid-API-key error. |
| 404 | The app is not registered in the key's workspace: {"code":404,"message":"No app found for this identifier in your workspace"}. The SDK sends the identifier the build has — a debug build with a suffixed ID needs its own registered app. | Not retried. Reported as a server error with status 404. |
| 429 | Too many requests from one IP address (currently 100 a minute on the SDK endpoints). This body is plain text, not JSON. | Retried with exponential backoff, honouring Retry-After, then reported as a server error with status 429. |
| 5xx | A backend error. | Retried the same way, then reported as a server error with that status. |
| 400 | The request failed validation. The SDKs should never send one — report it. | Not retried. Reported as a server error with status 400. |
By default the SDKs make 3 attempts, starting at a 0.5-second backoff and capped at 8 seconds; retryPolicy changes it (.disabled / DISABLED turns retries off). Network failures are retried the same way before they are reported as transport errors.
A failing install does not throw from configure and does not crash the app — it is only visible on onError and in the SDK logs. Watch both while integrating; Troubleshooting lists the usual causes by symptom.