Errors are grouped by where they come from in the SDK lifecycle. Each entry covers the message, the HTTP / SDK state it shows up in, and what to do about it.
The first argument to StreamConnect({ el }) was undefined, missing,
or not a string. Pass a CSS selector that resolves to a single
element on the page (e.g. '#react-hook').
The selector passed in el doesn't match anything when the SDK tries
to mount. Either the element doesn't exist yet (load the SDK after
your container element renders), or the selector is wrong. The SDK
calls handleInitErrors with the error so your host page can log /
recover.
The user object passed to StreamConnect({ user: ... }) is
missing one of the three required fields. Backend returns 422.
The email passed in user.email matches a TPAStream admin account.
Use a different email; admin accounts can't double as enrollment
users. For local testing the + alias trick works
(youremail+sdktest@gmail.com).
sdkToken / apiToken is missing from the init object. Both are the
same option (apiToken wins if both are set). Get the value from
TPAStream support.
sdkToken is valid but hasn't been activated yet (or has been
deactivated). Contact TPAStream support.
The SDK version being loaded predates a server-side change. Pinned CDN versions remain available indefinitely, so this is rare; usually it indicates a bundle that's older than any pinned release.
The fixCredentials: true init option requires a
connectAccessToken. Mint one server-side via
POST /api/create-connect-token (see
Connect Access Token) and pass it to
StreamConnect.
The Patient Access API flow (enablePatientAccessAPI: true) needs a
redirect URL registered with your sdkToken so the carrier knows where
to send the user after they authenticate. Contact TPAStream support
to configure this on the sdkToken.
These come from the /v3/sdk/progress/<task_id>/stream endpoint that
the 0.8 SDK uses for live validation updates. They are NOT shown to
the user directly. The SDK transitions the validation into a
recoverable state (failure or pending_async) and surfaces a copy
in the hero element.
| HTTP status | Detail message | Meaning | Recovery |
|---|---|---|---|
| 401 | Missing token |
The SSE URL was hit without a ?token= query param |
Shouldn't happen via the SDK; if you proxy the URL yourself, forward the token |
| 401 | Task token has expired |
JWT exp passed (10-minute TTL, sized to one connection) |
Re-fetch the policy holder for a fresh token and resubscribe. The SDK does this automatically |
| 401 | Task not available |
The Redis progress_task_owner pointer is gone: cleared on terminal state, or the ~90-minute observation window lapsed |
Usually means the task finished. Read the outcome from the validate-credentials GET rather than retrying the stream |
| 403 | Not your task |
The JWT and Redis pointer disagree on user_id |
Token reuse across sessions; re-init the SDK |
| 422 | Task token is invalid |
Bad signature, unknown algorithm, or malformed claims | Token was tampered with or minted by a different deploy |
| 422 | Task token does not match requested task |
The token's task_id claim doesn't match the URL path |
Token reuse against the wrong task; re-submit |
| 422 | Task token audience mismatch |
aud claim isn't sdk:sse:progress |
Token from a different service was forwarded |
| 422 | Task token missing required claim: <name> |
Mint upstream produced a token missing one of exp / iat / task_id / sub |
Backend bug; report it |
On any of these the SDK first tries to reattach (re-fetch the policy
holder for a fresh task_token, resubscribe), because the stream
failing says nothing about whether the validation is still running.
Only if that can't proceed does the validation go to pending_async
(visible in the hero / corner panel), and the wizard stays usable
throughout. The user can keep adding carriers; when they return later
the validation's true terminal state is reflected.
Task not available is the interesting one: the Redis pointer is
cleared the moment a task reaches a terminal state, so this now
usually means the validation finished, not that a window lapsed. The
SDK reads the outcome from the validate-credentials GET and shows the
real terminal state rather than asking the user to re-submit.
Generic transient error from the cred-submit POST. Often a brief
backend hiccup; user retry usually clears it. Surfaced in the inline
form error and via handleFormErrors so your host page can log.
The carrier's Patient Access API redirect returned a FAILURE state.
The carrier-specific message is forwarded verbatim from the carrier's
response. Common causes: user denied consent on the carrier page,
carrier-side auth failure, expired authorization grant.
The Patient Access API redirect couldn't begin because the carrier
has no interoperability_authorization_url configured on the backend
payer row. Not a customer-fixable problem; needs backend payer
config.
The getInteropState polling request rejected (network / auth /
server error). The SDK clears the interval, surfaces this message,
and lets the user retry the carrier auth from the start.
The interop polling endpoint returned a status the SDK doesn't know how to handle. Indicates a backend-frontend version skew; report it.
A required field on the credentials form is empty. Comes from the
Zod schema generated from the carrier's onboard_form.schema.
The "I have read and agree to the Terms of Use" checkbox wasn't ticked.
The tenant acknowledgement checkbox wasn't ticked.
- Client Usage for the full init option contract
and the
handleFormErrors/handleInitErrorscallback signatures - SDK Flow for how the wizard recovers from each error class
- Two-Factor Authentication for the MFA-specific error states