Errors

Master reference for every error code the SDK can surface. Each error follows the SDKError shape (code / message / kind / retriable?) and is delivered through one of the SDK's existing channels: Promise rejection or event payload. Codes are stable strings; switch on err.code for specific handling, or err.kind for grouped recovery.

Two delivery channels.
  • Promise rejection โ€” methods that return a Promise reject with an SDKError when they fail (e.g. VideoSDK.join(), me.publishVideo()). The Promise is the natural error channel for explicit calls.
  • Event payload โ€” for failures that happen async (no Promise to reject), the SDK fires an event with the error in the payload (e.g. me.on('stream-publish-failed', { kind, error })).

Error shape

interface SDKError { code: string; // stable identifier โ€” switch on this; never on `message` message: string; // human-readable, may evolve between SDK versions kind: ErrorKind; // category โ€” for grouped handlers retriable?: boolean; // true โ†’ calling again with same input might succeed }

See types.html โ€” SDKError for the full type definition with examples (generic retry helper, categorical handler).

By surface โ€” where each code can fire

Codes are scoped to the surface that produces them. The same code may fire on multiple surfaces (e.g. CAMERA_IN_USE can come from both an explicit publishVideo() rejection and an async stream-publish-failed event).

VideoSDK.join() โ€” Promise rejection

Fired when the join handshake fails. 21 codes. See VideoSDK.join.

codekindretriableWhenv0
INVALID_API_KEYAuthfalseAPI key revoked or never valid4001
INVALID_TOKENAuthfalseToken missing / malformed / expired4002
INVALID_PERMISSIONSAuthfalseToken's permissions claim is wrong4008
UNAUTHORIZED_ROOMAuthfalseToken not authorized for this roomId4022
UNAUTHORIZED_PARTICIPANTAuthfalseToken not authorized for this participantId4023
INVALID_ENTRY_CLAIMAuthfalseToken's joinPolicy is invalid โ€” mode: 'ask' with canModerate, ttl set with mode: 'direct', or ttl outside 10..600. Primary path: backend helper throws at mint time (no JWT created); server re-validates as a safety net for hand-rolled JWTs.โ€”
ENTRY_DENIEDAuthfalseA moderator clicked Deny on this joiner's lobby request.โ€”
ENTRY_TIMEOUTAuthtrueServer ttl fired before any moderator decided. Retry permitted within the rate-limit window.โ€”
ENTRY_RATE_LIMITEDAuthtrueToo many lobby attempts on the same token (default 3 per 5 minutes). Retry after the window.โ€”
INVALID_ROOM_IDConfigfalseRoom ID malformed / missing4003
INVALID_PARTICIPANT_IDConfigfalseBad participantId shape in JoinOptions4004
INVALID_PROTOCOL_PREFERENCEConfigfalsepreferredProtocol: UdpOnly requested but not availableโ€”
CONFLICTING_PUBLISH_CONFIGConfigfalseBoth pre-call stream AND JoinOptions.publishVideo set for same kindโ€”
STREAM_ALREADY_EXISTSConfigfalsePre-call singleton conflictโ€”
ROOM_FULLServertrueMax participants reached4009
DUPLICATE_PARTICIPANTServerfalseSame participantId already in room4005
ACCOUNT_DEACTIVATEDServerfalseOrganization account deactivated4006
ACCOUNT_DISCONTINUEDServerfalseOrganization account discontinued4007
NETWORK_ERRORNetworktrueSignaling unreachable / connection refused / ICE / DTLS โ€” SDK has retried internally; this is the give-upโ€”
TIMEOUTNetworktrueOverall join handshake exceeded SDK timeoutโ€”
BROWSER_UNSUPPORTEDConfigfalseWebRTC unavailable in this runtime3011/3012

me.on('stream-publish-failed', { kind, error }) โ€” event payload

Fired when any local publish fails โ€” initial attempt OR mid-call runtime failure of a previously-live stream. 14 codes. See LocalParticipant events. After this event, me.<kind> is null.

Initial publish failures โ€” capture / negotiation / acquisition. Also surface as Promise rejection on explicit me.publishVideo({}) calls.

codekindretriableWhenv0
CAMERA_IN_USEMediatrueAnother app holds the camera3023
MICROPHONE_IN_USEMediatrueAnother app holds the mic3024
CAMERA_NOT_FOUNDMediatrueNo camera connected3021
MICROPHONE_NOT_FOUNDMediatrueNo mic connected3022
MEDIA_PERMISSION_DENIEDPermissionfalseUser blocked the permission prompt3014/3015/3017/3018
INVALID_DEVICEMediafalsePassed device no longer exists (e.g. unplugged just before publish)โ€”
CONSTRAINT_FAILEDMediatrueResolution / framerate not supported by selected deviceโ€”

Mid-call runtime failures โ€” fire when a previously-live stream dies. Stream is gone after the event; me.<kind> becomes null. App can retry via me.publishVideo({}).

codekindretriableWhenv0
CAMERA_DEVICE_LOSTMediatrueCamera unplugged / disconnected mid-call3027
MICROPHONE_DEVICE_LOSTMediatrueMic unplugged / disconnected mid-call3028
CAMERA_PERMISSION_REVOKEDPermissionfalseOS revoked camera permission mid-callโ€”
MICROPHONE_PERMISSION_REVOKEDPermissionfalseOS revoked mic permission mid-callโ€”
SCREEN_SHARE_STOPPEDMediatrueUser clicked browser's "Stop sharing" buttonโ€”
ENCODER_FAILEDMediatrueVideo / audio encoder diedโ€”
TRACK_ENDEDMediatrueGeneric โ€” track ended for unknown reasonโ€”

room.pubsub.publish() โ€” Promise rejection

Errors that can reject the publish Promise. SDK-local errors (no round trip) listed first.

codeoriginkindretriablecause
INVALID_TOPIC_NAMESDKConfigfalseTopic violates naming rules (1โ€“128 chars from [a-zA-Z0-9_-:.])
PAYLOAD_TOO_LARGESDKConfigfalsePayload > 32 KiB after JSON encoding
INVALID_PAYLOADSDKConfigfalsePayload not JSON-serializable (circular ref, BigInt, Function, etc.)
NOT_CONNECTEDSDKNetworkfalsePublish called before join or after leave
RATE_LIMIT_EXCEEDEDServerNetworktruePer-topic publish rate exceeded (server policy)
PERMISSION_DENIEDServerPermissionfalseTopic restricted for this client by server policy
NETWORK_ERRORSDK/ServerNetworktrueTransient connection issue; SDK auto-retries 3ร— with backoff before rejecting
Idempotency on retry. SDK auto-retries NETWORK_ERROR with an internal idempotency key โ€” no duplicate messages even if multiple retries reach the server. App sees one final Promise resolve / reject.

Service start / stop โ€” Promise rejection

Errors that can reject the start / stop methods for room server-side services โ€” startRecording / stopRecording, startHls / stopHls, startLivestream / stopLivestream, startTranscription / stopTranscription. 2 codes. Both are SDK-local guard rejections โ€” raised before any wire call when the service is not in a valid state for the requested transition. State is read from the matching ServiceState getter (recordingState / hlsState / livestreamState / transcriptionState).

codeoriginkindretriablecause
ALREADY_STARTEDSDKServerfalseA start method was called while the service is not in a startable state. A service is startable only from ServiceState.Stopped or ServiceState.Failed; calling start while it is starting / started / stopping rejects with this code.
NOT_STARTEDSDKServerfalseA stop method was called while the service has nothing to stop. Stop is valid only from ServiceState.Starting or ServiceState.Started; calling stop while it is stopped / failed / stopping rejects with this code.
SDK-local โ€” no wire call. Both codes are rejected by the SDK before any request reaches the server. Neither is retriable: retrying with the same input fails identically until the service's ServiceState changes.

p.subscribe() / p.unsubscribe() โ€” Promise rejection

Errors that can reject subscribe / unsubscribe on a RemoteParticipant. Subscribe targets a kind on a specific participant; rejections cover the four failure modes (state, permission, identity, network).

codekindretriablecause
NOT_PUBLISHEDServerfalseThe target participant has not published the requested kind (or any one kind in an array โ€” subscribe arrays are all-or-nothing). Retrying the same call fails identically until the publisher actually publishes; the correct pattern is to subscribe in response to the stream-published event (which fires retroactively for already-published kinds + live for new ones). See RemoteParticipant.subscribe.
INVALID_PERMISSIONSAuthfalseYour token's grant lacks canSubscribe, or the target is a viewer-tier participant (isViewer: true) โ€” viewers don't publish media. See Authentication โ†’ grant.
PARTICIPANT_NOT_FOUNDServerfalseThe participant left between your call and the server ack.
NETWORK_ERRORNetworktrueTransient connection issue; SDK auto-retries before rejecting.
NOT_PUBLISHED is the "subscribe before publish" signal. It's not a retry-able fault โ€” calling subscribe repeatedly until they publish would just hammer the server. Listen to stream-published on the RemoteParticipant instead; that event fires retroactively for already-published kinds AND live for new ones, so a single handler covers the full subscribe lifetime.

Other surfaces โ€” TBD

Inventories for these surfaces will be locked as we complete the corresponding design topics. Each will list its closed code set here.

All codes โ€” alphabetical

Master cross-reference. Click any code to jump to the full description in its surface section above.

codekindretriableFired by
ACCOUNT_DEACTIVATEDServerfalseVideoSDK.join
ACCOUNT_DISCONTINUEDServerfalseVideoSDK.join
ALREADY_STARTEDServerfalseservice start methods
BROWSER_UNSUPPORTEDConfigfalseVideoSDK.join
CAMERA_DEVICE_LOSTMediatruestream-publish-failed
CAMERA_IN_USEMediatruestream-publish-failed + me.publishVideo() rejection
CAMERA_NOT_FOUNDMediatruestream-publish-failed + me.publishVideo() rejection
CAMERA_PERMISSION_REVOKEDPermissionfalsestream-publish-failed
CONFLICTING_PUBLISH_CONFIGConfigfalseVideoSDK.join
CONSTRAINT_FAILEDMediatruestream-publish-failed + me.publishVideo() rejection
DUPLICATE_PARTICIPANTServerfalseVideoSDK.join
ENCODER_FAILEDMediatruestream-publish-failed
ENTRY_DENIEDAuthfalseVideoSDK.join
ENTRY_RATE_LIMITEDAuthtrueVideoSDK.join
ENTRY_TIMEOUTAuthtrueVideoSDK.join
INVALID_API_KEYAuthfalseVideoSDK.join
INVALID_DEVICEMediafalsestream-publish-failed + me.publishVideo() rejection
INVALID_ENTRY_CLAIMAuthfalseVideoSDK.join (mint-time helper + server safety net)
INVALID_PARTICIPANT_IDConfigfalseVideoSDK.join
INVALID_PERMISSIONSAuthfalseVideoSDK.join
INVALID_PROTOCOL_PREFERENCEConfigfalseVideoSDK.join
INVALID_ROOM_IDConfigfalseVideoSDK.join
INVALID_TOKENAuthfalseVideoSDK.join
MEDIA_PERMISSION_DENIEDPermissionfalsestream-publish-failed + me.publishVideo() rejection
MICROPHONE_DEVICE_LOSTMediatruestream-publish-failed
MICROPHONE_IN_USEMediatruestream-publish-failed + me.publishAudio() rejection
MICROPHONE_NOT_FOUNDMediatruestream-publish-failed + me.publishAudio() rejection
MICROPHONE_PERMISSION_REVOKEDPermissionfalsestream-publish-failed
NETWORK_ERRORNetworktrueVideoSDK.join
NOT_PUBLISHEDServerfalsep.subscribe()
NOT_STARTEDServerfalseservice stop methods
ROOM_FULLServertrueVideoSDK.join
SCREEN_SHARE_STOPPEDMediatruestream-publish-failed
STREAM_ALREADY_EXISTSConfigfalseVideoSDK.join + VideoSDK.createVideoStream()
TIMEOUTNetworktrueVideoSDK.join
TRACK_ENDEDMediatruestream-publish-failed
UNAUTHORIZED_PARTICIPANTAuthfalseVideoSDK.join
UNAUTHORIZED_ROOMAuthfalseVideoSDK.join

See also: SDKError ErrorKind