livqenoDocs

ResourcesErrors

Errors

Every error code Livqeno can return, what it means, and how to fix it.

This page lists every error code, what it means, and how to fix it. Come here when you have an error code in a log or on screen and need to know where it came from and what to change.

Errors happen at different steps of the flow — your backend minting a token, your user's app joining a call, a chat connection — and each step has its own list of codes. So the first question is: which step failed?

Which list is my error from?

You saw the error…It's fromLook in
In your backend, when an @livqeno/server / livqeno call or a curl request failedThe REST APIHTTP error codes (RAVEN_*)
In your browser or phone app, thrown by join() or in room.on('error')The RTC SDKRTC SDK errors
In your app's chat code, or as a chat WebSocket close code (44xx)ChatChat errors
In a raw RTC signaling frame, or an RTC WebSocket close code (40xx)SignalingSignaling errors
In the dashboard, livqeno errors list, or the Observability API, as a category like ICE_ERRORLivqeno's error analysisRTC error categories

Some names, like TOKEN_EXPIRED, appear in more than one list. Use the table above to know which one you're looking at.

Summary of the four lists:

ListWhere you see itHow many
RAVEN_*The code field of any HTTP error34
RTCErrorCodeErrors thrown or emitted by @livqeno/rtc13
ChatErrorCodeThe chat WebSocket error frame and @livqeno/chat26
SignalingErrorCodeThe RTC signaling WebSocket error frame20

There are also RTC error categories. These aren't response codes. They're labels Livqeno puts on failures after they happen, to help you debug.

What an HTTP error looks like

Any REST call can fail this way: from your backend with the API key, or from the dashboard and CLI. The body always has the same shape:

{
  "code": "RAVEN_ROOM_NOT_FOUND",
  "legacyCode": "NOT_FOUND",
  "message": "Room not found",
  "requestId": "req_d4a74eaeb970633fc42414a6",
  "path": "/v1/rooms/2f1b6c3e-8d4a-4b7e-9c21-5a0e7d3f9b10"
}

A validation error (RAVEN_VALIDATION_FAILED, 400) has two extra fields, statusCode and error. Its message can be a list, one entry per bad field:

{
  "message": ["environment must be one of the following values: DEVELOPMENT, STAGING, PRODUCTION"],
  "error": "Bad Request",
  "statusCode": 400,
  "code": "RAVEN_VALIDATION_FAILED",
  "legacyCode": "VALIDATION_FAILED",
  "requestId": "req_7f9f475ddcab0cb6f554f253",
  "path": "/v1/projects/…/api-keys"
}

So treat message as string | string[]. Ids in the URL are UUIDs. A badly formed id gets a 400, not a 404.

FieldWhat it is
codeThe error code. Check this one.
legacyCodeOld, don't use. The code from before RAVEN_* existed. Will be removed.
messageA readable message. Safe to log. Never contains secrets.
requestIdSame as the x-request-id header. Include it in bug reports.
pathThe endpoint that failed.

Some errors add more fields. For example, a 429 adds retryAfterSeconds. Ignore fields you don't know.

Catching errors on your backend

The server SDKs throw one error type, LivqenoError, with the same code and requestId as the HTTP body. A typical token endpoint on your backend (TypeScript):

import { isLivqenoError } from '@livqeno/server';
 
try {
  const grant = await livqeno.tokens.create({ room: roomId, identity: req.user.id });
  res.json(grant);
} catch (error) {
  if (isLivqenoError(error)) {
    // Log requestId so you can match this to Livqeno's records later.
    console.error(error.code, error.requestId);
    if (error.code === 'RAVEN_ROOM_NOT_FOUND') return res.status(404).end();
  }
  throw error;
}

HTTP error codes

These come back from the REST API. You'll mostly see them in your backend, when it creates rooms, tokens, or conversations with the API key. The dashboard and CLI show them too.

Login and access

Something is wrong with the credential itself: a bad API key, an expired token, or a dashboard sign-in that didn't finish.

CodeHTTPWhat it meansHow to fix
RAVEN_AUTH_ERROR401The credential is missing, broken, or rejectedCheck the Authorization header, and that the key wasn't revoked
RAVEN_TOKEN_EXPIRED401The token has expiredMake a new token. You don't need to log the user in again
RAVEN_PERMISSION_DENIED403You're logged in, but not allowed to do thisCheck the token's permissions, or the user's project role
RAVEN_OAUTH_ERROR401OAuth sign-in didn't finish: expired state, failed code exchange, or the user cancelledStart the sign-in again. Always safe
RAVEN_OAUTH_EMAIL_UNAVAILABLE400The sign-in provider didn't give an email. Livqeno accounts need oneFix it at the provider (for example, GitHub with no verified main email)
RAVEN_OAUTH_EMAIL_UNVERIFIED403An account exists for this email, but the provider hasn't verified itVerify the email at the provider. (Linking it anyway would allow account takeover)

Not found

The thing doesn't exist for this credential. It may exist in another project or environment.

CodeHTTPWhat wasn't found
RAVEN_NOT_FOUND404Something (no more specific code fits)
RAVEN_PROJECT_NOT_FOUND404The project, or it isn't yours
RAVEN_ROOM_NOT_FOUND404An RTC room
RAVEN_PARTICIPANT_NOT_CONNECTED404A live session for that identity in the room (the moderation and metadata routes under /v1/rooms/:roomId/participants/:identity), or anyone at all for POST /v1/rooms/:roomId/data. They left, or never joined
RAVEN_TRACK_NOT_FOUND404A track that participant is publishing (server mute with a trackId)
RAVEN_CONVERSATION_NOT_FOUND404A chat conversation
RAVEN_MESSAGE_NOT_FOUND404A message in this project
RAVEN_ATTACHMENT_NOT_FOUND404An attachment, or it isn't uploaded yet
RAVEN_STREAM_NOT_FOUND404A live stream
RAVEN_RTC_SERVER_NOT_FOUND404A media server with that name

Conflicts

The request is valid, but clashes with something that already exists. The most common one: two users join at once and both try to create the same room.

CodeHTTPWhat it meansHow to fix
RAVEN_CONFLICT409The name is taken, or the thing is already in that stateUse getOrCreate, or a different name
RAVEN_MESSAGE_ALREADY_EXISTS409A clientMessageId was sent twiceNothing to fix. The retry was caught. Treat it as success
RAVEN_CONVERSATION_ARCHIVED409The conversation is archived. You can read but not writeUnarchive it first
RAVEN_STREAM_INVALID_STATE409Not allowed in the stream's current state (like starting a stream that's already LIVE, or anything on an ENDED one)Check the status first. ENDED is final
RAVEN_IDEMPOTENCY_KEY_IN_USE409Another request with the same Idempotency-Key is still running. Includes retryAfterSecondsWait that many seconds and retry with the same key. You get the first request's response

Bad requests

The request itself is wrong: a typo in a field name, a value out of range, or a body that's too big. Fix the request; retrying it unchanged won't help.

CodeHTTPWhat it meansHow to fix
RAVEN_VALIDATION_FAILED400The body or query is wrong. Unknown fields are rejected too, not ignoredCheck spelling against the parameter tables
RAVEN_INVALID_CURSOR400The pagination cursor can't be readStart paging again from the beginning, on purpose
RAVEN_PAYLOAD_TOO_LARGE413The request is too bigSend less
RAVEN_MESSAGE_TOO_LARGE413Message text or metadata is too longLimit is 4000 characters / 4096 bytes by default
RAVEN_ATTACHMENT_TOO_LARGE413The file is bigger than STORAGE_MAX_ATTACHMENT_BYTESLimit is 25 MB by default
RAVEN_RATE_LIMITED429Too many requests. Includes retryAfterSecondsWait that many seconds, then retry

MESSAGE_TOO_LARGE and ATTACHMENT_TOO_LARGE are separate codes so you know which limit you hit.

RTC tokens

CodeHTTPWhat it meansHow to fix
RAVEN_RESERVED_IDENTITY422participantIdentity starts with a prefix Livqeno reserves for its own participants (egress-, relay-, capture-, transcriber-, agent-). The response's prefix names itUse a different identity, for example prefix your own ids with user-

Usage limits

Your account has hit one of its free allowances or free-tier limits. You'll usually see these when your backend mints a token or creates a stream.

CodeHTTPWhat it meansHow to fix
RAVEN_USAGE_LIMIT_EXCEEDED403One of your three free allowances (RTC minutes, chat messages, live-streaming host-hours) is used upPermanent. Waiting won't help. Move to a paid plan
RAVEN_PROJECT_LIMIT_EXCEEDED403A free-plan account already owns 3 active projectsTemporary. Archive or delete a project you no longer use, or move to a paid plan
RAVEN_STREAM_CONCURRENCY_LIMIT_EXCEEDED403Your account already has a LIVE stream. The free tier allows one at a timeTemporary. End the other stream, or wait for it to end
RAVEN_STREAM_VIEWER_LIMIT_EXCEEDED403The stream has the maximum number of viewers for the free tierTemporary. Try again when a viewer leaves
RAVEN_BILLING_SPEND_CAP_REACHED403Paid plan: this month reached your spend capRaise or clear the cap in the dashboard under Billing
RAVEN_BILLING_ACCOUNT_SUSPENDED403Paid plan: an invoice is unpaid past its grace periodPay it in the dashboard under Billing

The last two are separate from USAGE_LIMIT_EXCEEDED so you can tell "wait" apart from "nothing left". A paid plan lifts all three.

Infrastructure

Something outside your request went wrong.

CodeHTTPWhat it meansHow to fix
RAVEN_CONNECTION_FAILED—A realtime connection couldn't be madeSee RTC troubleshooting
RAVEN_NO_RTC_CAPACITY—No media server had roomA Livqeno-side problem, not yours. Try again later
RAVEN_WEBHOOK_FAILED—A webhook delivery failedCheck the deliveries endpoint
RAVEN_NOT_CONFIGURED501This feature isn't turned on. Usually attachments with no STORAGE_BUCKETA platform-side fix
RAVEN_INTERNAL_ERROR500Something unexpected went wrongReport it with the requestId

Errors from the server SDK itself

@livqeno/server and livqeno raise these before a request is sent, so they never appear in an HTTP response. They use the same RAVEN_* names, so one switch handles everything:

CodeWhat it means
RAVEN_INVALID_CONFIGNo config object, or no apiKey
RAVEN_TIMEOUTThe request took too long (10 seconds by default)
RAVEN_NETWORK_ERRORThe request never reached Livqeno
RAVEN_UNKNOWN_ERRORNothing more specific is known

If a proxy returns an HTML error page instead of JSON, the SDK picks the code from the HTTP status. It uses the same code the API would have sent. For example, a 401 is always RAVEN_AUTH_ERROR.

legacyCode and old code

Before RAVEN_* codes existed, code held short values like NOT_FOUND, UNAUTHORIZED, and VALIDATION_FAILED. Every error now has both:

if (error.code === 'NOT_FOUND') { … }        // old — now error.legacyCode
if (error.code === 'RAVEN_ROOM_NOT_FOUND') { … }   // new

Several new codes map to the same old one, so the new codes tell you more. legacyCode is old and will be removed. Switch to code.

RTC SDK errors

These come from the RTC SDK in your user's browser or phone app: either thrown by join() and device calls like enableCamera(), or delivered to room.on('error'). @livqeno/rtc only ever throws or emits RTCError. Never a raw browser DOMException.

CodeWhat it meansHow to fix
INVALID_TOKENThe token is broken, or token / endpoint is missingPass the token response to the client unchanged
TOKEN_EXPIREDThe token had already expired when the client was createdMake the token right before joining, not when the page loads
ROOM_NOT_FOUNDjoin() got a room the token wasn't made forUse the room id or name from the token response
PERMISSION_DENIEDThe token doesn't allow thisFix the permissions when making the token
CAMERA_PERMISSION_DENIEDThe user blocked camera accessExplain in your own UI. The OS won't ask twice
MICROPHONE_PERMISSION_DENIEDThe user blocked microphone accessSame as above
DEVICE_NOT_FOUNDThe device doesn't exist, or was unpluggedList devices again with getDevices()
NETWORK_ERRORA network failureCheck the connection and retry
SIGNALING_ERRORThe signaling handshake didn't finishCheck endpoint is reachable and uses wss://
MEDIA_ERRORA media action failedWorth retrying
INVALID_ARGUMENTAn argument broke a documented limit: a sendData() payload, topic or destination list that is too big, or metadata or an attribute over its size limit. The same code on every platformFix the call. Retrying the same arguments fails again
NOT_SUPPORTEDThe device can't do this at all (like screen sharing with no getDisplayMedia)Permanent. Hide the button. Don't retry
CONNECTION_FAILEDThe connection (ICE/DTLS) couldn't be madeUsually TURN. See troubleshooting
TIMEOUTSomething took too longRetry

NOT_SUPPORTED means "never on this device". MEDIA_ERROR means "try again".

Handle them in your app code, and show the user something useful:

import { isRTCError } from '@livqeno/rtc';
 
room.on('error', (error) => {
  if (!isRTCError(error)) return;
  if (error.code === 'CAMERA_PERMISSION_DENIED') showPermissionHelp();
  if (error.code === 'NOT_SUPPORTED') hideFeature();
});

RTC error categories

You won't catch these in code. You'll see them when investigating a failed call afterwards. When a client reports a failure, Livqeno gives it a category to help you debug. You see these in the dashboard, in livqeno errors list, and in the observability API. They're never returned as a response code.

CategoryWhat it means
AUTHENTICATION_ERRORThe credential was rejected
AUTHORIZATION_ERRORLogged in, but not allowed
TOKEN_ERRORThe RTC token was invalid, broken, or expired
SIGNALING_ERRORThe signaling handshake didn't finish
ICE_ERRORThe connection checks failed. Usually a firewall or NAT
TURN_ERRORThe TURN relay couldn't be reached
SFU_ERRORThe media server couldn't finish, for no more specific reason
NETWORK_ERRORA general network failure or timeout
CLIENT_ERRORA problem on the device: wrong room, device permission, media error
UNKNOWN_ERRORNothing more specific is known

How CONNECTION_FAILED is categorized, checked in this order:

  1. A turn_unreachable hint → TURN_ERROR
  2. A failed iceConnectionState → ICE_ERROR
  3. Signaling never became stable → SIGNALING_ERROR
  4. Anything else → SFU_ERROR

Each categorized error has a likelyCause and a suggestedAction. They're worded as "likely", because the server can't be certain.

Chat errors

These come from chat: the chat SDK in your user's app, the chat WebSocket, or chat REST calls. @livqeno/chat has 26 codes. The server can send 22 of them in an error frame. Each code maps to one SDK error class, so you can check the class instead of comparing strings.

CodeHTTPSDK classWhat it means
INVALID_TOKEN401LivqenoChatAuthenticationErrorThe token is missing, broken, or signed wrong
TOKEN_EXPIRED401LivqenoChatAuthenticationErrorMake a new token. Handle onTokenExpiring
TOKEN_REVOKED401LivqenoChatAuthenticationErrorThe token was revoked before it expired
UNAUTHORIZED401LivqenoChatAuthenticationErrorNo usable credential was sent
PERMISSION_DENIED403LivqenoChatPermissionErrorThe token's scope or the user's role doesn't allow this
NOT_A_MEMBER403LivqenoChatPermissionErrorNot a member of that conversation. Only an API key sees this; a chat token gets ROOM_NOT_FOUND, so conversation names stay hidden
ORIGIN_NOT_ALLOWED403LivqenoChatPermissionErrorThe page's Origin isn't on the project's Allowed Origins list. Add it under Settings → Security → Allowed Origins
ROOM_NOT_FOUND404LivqenoRoomErrorNo such conversation in this project
NOT_IN_ROOM400LivqenoRoomErrorThis connection hasn't joined that conversation
TOO_MANY_SUBSCRIPTIONS400LivqenoRoomErrorThis connection has joined too many conversations
CONVERSATION_ARCHIVED409LivqenoRoomErrorArchived. You can read but not write
MESSAGE_NOT_FOUND404LivqenoMessageErrorNo such message
MESSAGE_DELETED409LivqenoMessageErrorThe message was deleted
MESSAGE_TOO_LARGE413LivqenoMessageErrorText, metadata, or frame is too big
INVALID_MESSAGE400LivqenoMessageErrorBroken, or missing a required field
INVALID_MESSAGE_TYPE400LivqenoMessageErrorFrame or message type isn't supported
INVALID_CURSOR400LivqenoMessageErrorThe pagination cursor is broken
RATE_LIMITED429LivqenoRateLimitErrorToo many requests. Includes retryAfterSeconds
ATTACHMENT_NOT_FOUND404LivqenoAttachmentErrorNo such attachment
ATTACHMENTS_NOT_CONFIGURED501LivqenoAttachmentErrorFile storage isn't turned on
ATTACHMENT_TOO_LARGE413LivqenoAttachmentErrorBigger than STORAGE_MAX_ATTACHMENT_BYTES
CONNECTION_FAILED—LivqenoChatConnectionErrorCouldn't connect, or ran out of reconnect attempts
CONNECTION_CLOSED—LivqenoChatConnectionErrorThe connection closed before the server replied
NETWORK_ERROR—LivqenoChatConnectionErrorThe request never reached Livqeno
TIMEOUT—LivqenoChatConnectionErrorNo reply in time
INTERNAL_ERROR500LivqenoChatErrorSomething went wrong on the server. It's logged in full

Chat WebSocket close codes

When the chat connection closes, the close code tells the app whether reconnecting makes sense. The SDK reads it for you; you only need this table if you're debugging or using the raw WebSocket.

CodeWhat it meansReconnect?
1000Normal closeNo
4401Login failedNo. Retrying won't help
4403Origin not allowedNo. Add it to the project's Allowed Origins
4429Too many connection attemptsYes, after waiting
4440Token expiredYes, with a new token
4500Server shutting downYes, after waiting. It's a deploy, not a fault

@livqeno/chat stops on 4401 and 4403 and reports failed, instead of retrying forever.

Signaling errors

Signaling is the WebSocket an app opens to join a call; it's how the app and the media server agree how to connect. You'll only handle these codes directly if you speak the protocol yourself. With the SDK, you'll usually see them turned into an RTCError, or in logs.

The RTC signaling WebSocket has its own error codes, because it is a separately versioned protocol. You see them in an error frame. The SDK turns most of them into an RTCError.

CodeWhat it meansRetry?
INVALID_TOKENThe token is broken or signed wrongNo
TOKEN_EXPIREDThe token expired before or while connectingYes, with a new token
TOKEN_REVOKEDSomeone revoked this token on purpose. Sent at connect, and to a session already running on it (which then ends)No. Ask your backend for a new one
TOKEN_INVALIDA token.refresh was refused (bad token, or one for a different room or identity). The session keeps going on its current tokenYes, with another token, before the current one expires
UNAUTHORIZEDNo usable credentialNo
ROOM_NOT_FOUNDNo such room in this project and environmentNo
ROOM_FULLThe room has SIGNALING_MAX_PARTICIPANTS_PER_ROOM peopleNo
ROOM_CLOSEDThe room was closed while you were in it (DELETE /v1/rooms/:id, or its live stream ended)No. A new token won't get back in
INVALID_MESSAGEA broken frameNo
INVALID_MESSAGE_TYPEA frame type that isn't supportedNo
PARTICIPANT_NOT_FOUNDThat participant isn't in the roomNo
NOT_IN_ROOMTried to do something before joiningNo
PERMISSION_DENIEDThe token doesn't allow this (like publishing without publish)No
ORIGIN_NOT_ALLOWEDThe page's Origin isn't on the project's Allowed Origins listNo. Add it under Settings → Security → Allowed Origins
RATE_LIMITEDToo many messages on this connectionYes, after waiting
USAGE_LIMIT_EXCEEDEDThe account has used all its included minutes. Calls already running are never cut offNo. Waiting won't help
NO_RTC_CAPACITYNo media server had roomA Livqeno-side problem
RTC_SERVER_UNREACHABLEThe chosen media server couldn't be reachedYes
NEGOTIATION_FAILEDSetup failed and can't recoverNo. Rejoin
NEGOTIATION_GLAREAn offer is already on its wayYes. Answer the incoming offer, then retry

The full message format is in Signaling protocol.

Close codes

These are the RTC signaling close codes (40xx). Don't confuse them with the chat close codes above (44xx).

When the server closes the signaling connection, it uses one of these codes. Where it applies, it sends an error frame first.

CodeWhyWhat to do
1012The server is restarting (a deploy)Reconnect after a random 0–2 s, resuming the session. The SDKs do this for you
4001Login failed: bad, expired, or revoked token, or the Origin isn't allowed. Also sent when a session's token expires mid-call and the server enforces expiryGet a new token (or fix Allowed Origins). Don't retry the same one. With refreshToken set, the SDKs refresh and reconnect for you
4002Replaced: a newer connection joined as the same participantNothing. The newer tab or device has the session now
4003The participant was removed by your backend, or the room was closed (DELETE /v1/rooms/:id, or its live stream ended)Leave. Don't reconnect. The SDKs report disconnected with reason REMOVED or ROOM_CLOSED
4004The media server for this session went awayReconnect. You'll get a healthy server
4029Too many connection attemptsWait, then reconnect

Next steps