# Recebi o código X, o que eu faço? [#recebi-o-código-x-o-que-eu-faço] > Pergunta: "recebi o código X, o que eu faço?" **Gerada** do catálogo de erro (`src/error-catalog.ts`, `ERROR_CATALOG`) — não editar à mão. Rode `cd packages/event-room && npm run docs:generate` depois de mudar o catálogo; `npm run build` (no mesmo diretório) falha se este arquivo divergir da regeneração. ## Como ler a tabela [#como-ler-a-tabela] Toda linha tem o `remedy` — a ação a tomar — ao lado do código, nunca em outra página. `retryable` diz se tentar de novo automaticamente faz sentido; quando não, a ação é sempre humana ou de outro tipo (reautenticar, reescanear, trocar de contrato). Um código que não está nesta tabela é desconhecido desta versão da lib — ele ainda chega como observação não-terminal, nunca é descartado (`code`, `known: false`), mas não tem `remedy` específico: trate como falha de serviço genérica e considere reportar. ## As quatro categorias [#as-quatro-categorias] * **usage (erro de programação — lança síncrono, antes de qualquer I/O)**: `access_mode_required`, `already_attached`, `contract_async_validator`, `contract_invalid_definition`, `contract_required`, `contract_reserved_prefix`, `contract_too_large`, `creator_required`, `credential_required`, `display_name_required`, `event_not_in_contract`, `event_payload_invalid`, `event_unknown_to_peer`, `guest_url_reserved_param`, `host_closed`, `invalid_access_mode`, `invalid_event`, `invalid_guest_url`, `invalid_max_guests`, `invalid_room_id`, `join_already_pending`, `join_code_required`, `malformed_join_target`, `not_joined`, `payload_too_large_client`, `qr_url_required`, `request_id_required`, `request_not_found`, `role_required`, `room_id_collision`, `room_id_generation_exhausted`, `room_still_open`, `unknown_role`, `unsupported_guest_url_scheme`, `unsupported_qr_runtime` * **flow (condição de jornada — rejeita a promise da chamada causadora)**: `creator_replaced`, `join_rejected`, `room_already_exists`, `room_full`, `too_many_code_attempts` * **ended (fim de sessão — estado terminal com `reason`)**: `protocol_version_mismatch` * **infra (falha de serviço/código desconhecido — observação não-terminal, nunca silenciada)**: `bad_json`, `bad_message`, `event_not_allowed`, `event_out_of_contract`, `idle_timeout`, `invalid_creator_token`, `invalid_join_code`, `occupancy_limit_not_honored`, `payload_too_large`, `room_not_found`, `room_rate_limited`, `service_unavailable`, `unknown_type` ## Tabela completa [#tabela-completa] | code | category | remedy | retryable | | ------------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | | `access_mode_required` | usage | accessMode is mandatory — there is no default in code — for both createHost and startRoom. | não | | `already_attached` | usage | This connection already has a room association — this library should never send a second create/join on an already-associated connection. | não | | `bad_json` | infra | The server could not parse a wire message as JSON. | não | | `bad_message` | infra | The server rejected a malformed wire message. | não | | `contract_async_validator` | usage | Contract validators must be synchronous — an async/Promise-returning validator was supplied. | não | | `contract_invalid_definition` | usage | The contract definition is not a valid shape node. | não | | `contract_required` | usage | send() requires a contract — pass one to createHost/joinRoom to traffic app events. | não | | `contract_reserved_prefix` | usage | Event names starting with the reserved protocol prefix cannot be part of an app contract. | não | | `contract_too_large` | usage | The contract's digest map exceeds the fingerprint budget — split or shrink the contract. | não | | `creator_replaced` | flow | Another connection took over as this room's creator while this specific call was in flight. | não | | `creator_required` | usage | Only the room's creator connection may perform this action — this library should not have offered it otherwise. | não | | `credential_required` | usage | credential is required — the guest/host's own logged-in session, opaque to this library. There is no "credential: none". | não | | `display_name_required` | usage | This accessMode requires approval — pass displayName before connecting. | não | | `event_not_allowed` | infra | The reserved protocol event was rejected by the server's deploy whitelist (ALLOWED\_EVENTS) — a deploy configuration problem, not a code bug in the calling app. | não | | `event_not_in_contract` | usage | This event name is not declared in the local contract — add it to defineContract, or fix the typo. | não | | `event_out_of_contract` | infra | Received an event the local contract does not declare, or whose payload does not match the declared shape — not delivered to any handler. | não | | `event_payload_invalid` | usage | This payload does not match the shape declared for this event in the local contract. | não | | `event_unknown_to_peer` | usage | The peer's exchanged contract fingerprint does not declare this event name. The peer is running an outdated or divergent contract — update the peer, not this side. | não | | `guest_url_reserved_param` | usage | A reserved query param already exists on the guest URL — pass a URL without it, this library will not silently overwrite it. | não | | `host_closed` | usage | This host has already been closed (host.close()) — create a new one with createHost. | não | | `idle_timeout` | infra | The connection was idle without being associated to a room and the server closed it. Reconnect (a fresh call) to try again. | não | | `invalid_access_mode` | usage | accessMode was not one of the server's known access modes — this library validates accessMode client-side and should never let an invalid one through. | não | | `invalid_creator_token` | infra | The creator token was not recognized — another connection now controls this room. | não | | `invalid_event` | usage | The wire event name was invalid or reserved — this library controls the one reserved protocol event name and should never send a bad one. | não | | `invalid_guest_url` | usage | The guest URL could not be parsed. | não | | `invalid_join_code` | infra | The join code was wrong. Non-terminal for this connection — ask the user to re-enter it. | não | | `invalid_max_guests` | usage | maxGuests must be a positive integer — this library should validate it client-side before sending createHost/startRoom. | não | | `invalid_room_id` | usage | roomId does not match the server's expected shape — this library should have generated/validated a conforming id before sending. | não | | `join_already_pending` | usage | A join request is already pending on this connection — this library should never send a second join before the first resolves. | não | | `join_code_required` | usage | This accessMode requires a joinCode and none was provided. | não | | `join_rejected` | flow | The host rejected this join request. This attempt is over — reconnecting is a new admission, subject to a new approval. | não | | `malformed_join_target` | usage | target is malformed — expected \{roomId, accessMode, joinCode?}. | não | | `not_joined` | usage | An event was sent before joining a room — this library should not allow sendEvent before a room association exists. | não | | `occupancy_limit_not_honored` | infra | The requested maxGuests was not honored by the server — the effective limit is reported alongside room creation. | não | | `payload_too_large` | infra | The server rejected an event payload as too large for its configured limit. | não | | `payload_too_large_client` | usage | The serialized event payload exceeds the usable budget for this event name. This library does not slice payloads — shrink it yourself before sending. | não | | `protocol_version_mismatch` | ended | Peer protocolVersion does not match this side's — there is no dual-stack support. Retrying will not help; update whichever side is running the older/newer build. | não | | `qr_url_required` | usage | generateQrImageDataUrl requires a non-empty url — pass the output of buildJoinUrl. | não | | `request_id_required` | usage | A join-decision requestId was missing — this library should always supply the id it was handed via onJoinRequest. | não | | `request_not_found` | usage | The join request no longer exists (already decided or expired) — this library should track pending requests and not decide on a stale one. | não | | `role_required` | usage | joinRoom requires role — it is never inferred from target, and the QR never carries it. | não | | `room_already_exists` | flow | roomId collided with an existing room. A caller-supplied roomId is not retried; a generated one is retried automatically by this library. | sim | | `room_full` | flow | The room already has effectiveMaxGuests guests. This attempt is over — the caller decides whether to retry, wait, or surface this to the user; the library never retries automatically. | não | | `room_id_collision` | usage | The caller-supplied roomId is already in use. This library never retries a caller-supplied id — pass a different one or omit roomId to let this library generate one. | não | | `room_id_generation_exhausted` | usage | Could not generate a free roomId after several attempts — extremely unlikely; check the server's room registry health. | não | | `room_not_found` | infra | The room no longer exists — it may have expired or been closed between the QR scan/typed code and this attempt. | não | | `room_rate_limited` | infra | Too many joinCode attempts against this room in a short window — the server is rate-limiting. Wait before trying again. | sim | | `room_still_open` | usage | startRoom() was called while the current session is still live — call room.close() before restarting. | não | | `service_unavailable` | infra | The server reported itself temporarily unavailable. | sim | | `too_many_code_attempts` | flow | Too many wrong joinCode attempts — the server closed this attempt. Ask the user to re-scan/re-enter and try again; this library never retries a code guess automatically. | não | | `unknown_role` | usage | role is not one of the known guest roles. The server accepts any string, but this library validates it at runtime so a bad value never reaches the wire unnoticed. | não | | `unknown_type` | infra | The server did not recognize a wire message's `type`. | não | | `unsupported_guest_url_scheme` | usage | The guest URL scheme is on the fixed refusal list and cannot be used. | não | | `unsupported_qr_runtime` | usage | event-room/qr only supports the "browser" runtime (it needs `document`) — generate the join URL with buildJoinUrl and render the QR another way outside a browser. | não | ## Limite: o que `usage` garante sobre detectabilidade sem rede [#limite-o-que-usage-garante-sobre-detectabilidade-sem-rede] A maioria dos códigos `usage` lança **antes de qualquer I/O** — são erros de programação puros (credencial ausente, `role` desconhecido, payload grande demais). **Um deles não é assim**: `event_unknown_to_peer` só existe **depois do handshake de prontidão** (a fingerprint do peer precisa ter chegado para saber se ele conhece o evento) — é `usage`, lança síncrono no ponto de chamada de `sendEvent`, mas depende de uma rodada de rede já ter acontecido antes. `usage` não é sinônimo de "detectável sem nunca ter tocado a rede"; é sinônimo de "erro de chamada, não de servidor".