# Error Catalogue [← Home](Home.md) Every variant of [`VoiceError`](https://github.com/voicetastic/voicetastic-core/blob/main/crates/voicetastic-core/src/voice/error.rs), what triggers it, and how a caller should handle it. The assembler returns errors via `AssemblyEvent::Rejected(VoiceError)`; the builder returns them as `Result`. --- ## Header / structure errors (parse time) | Variant | Trigger | Handle | |------------------------|---------------------------------------------------------|-----------------------------------------| | `TooShort { len, needed }` | Frame shorter than `HEADER_SIZE = 16 B`. | Drop. Probably a non-voice packet. | | `TooLarge { len, max }` | Frame larger than `MAX_PACKET_SIZE = 231 B`. | Drop; sender is broken. | | `BadVersion(b)` | First byte ≠ `0x03`. | Drop; V2 or future protocol version. | | `ReservedFlagSet(b)` | Any reserved bit of `type_flags` is set (mask `0x2F`). | Drop; V2 frame or sender bug. | | `ReservedPacketType` | `packet_type == 3`. | Drop; reserved. | | `ZeroMessageId` | `message_id == 0`. | Drop; spec forbids zero. | | `BadTotal(0)` | `total_data == 0`. | Drop; spec forbids. | | `TooMuchParity(n)` | `parity_count > 128`. | Drop; FEC coder limit. | | `BadIndex { idx, total }` | `chunk_index ≥ total_data` (DATA) or `≥ parity_count` (PARITY). | Drop. | | `ParityCountDecrease { first, got }` | A later frame's `parity_count` is less than the value the first frame established (it MAY grow on retransmit, MUST NOT shrink). | Drop. | ## Body / chunk-size errors | Variant | Trigger | Handle | |---------------------------------------|------------------------------------------------------------------------|------------------------------| | `ChunkTooSmall(n)` | Builder: `chunk_size < MIN_CHUNK_SIZE`. | Sender bug. | | `ChunkTooLarge { got, max }` | Body length out of `MIN_CHUNK_SIZE..=MAX_BODY_SIZE` (assembler) or oversized chunk_size (builder). | Drop / sender bug. | | `BodyLenMismatch { got, expected }` | DATA / PARITY body length differs from established `chunk_size` (excluding final DATA, which may be shorter). | Drop. | | `AudioTooLarge { bytes, max }` | Builder: input audio exceeds `MAX_CHUNKS_PER_MESSAGE × chunk_size`. | Sender splits or compresses. | ## Codec / template errors | Variant | Trigger | Handle | |------------------------------------------|----------------------------------------------------------|---------------------------------------| | `UnknownCodec(b)` | Codec byte is unassigned (not 0..=3). | Drop; surface "codec unsupported". | | `UnsupportedCodec(codec)` | Codec is known but not in this receiver's `supported_codecs` set (e.g. an Opus-only build hearing AMR-NB). Rejected before any reassembly state is allocated. | Drop; surface "codec unsupported". | | `CodecMismatch { first, got }` | Frame's codec ≠ first frame's codec. | Drop; counts a validation strike. | | `TotalMismatch { first, got }` | Frame's `total_data` ≠ first frame's `total_data`. | Drop; counts a validation strike. | | `StreamSeqMismatch { first, got }` | Frame's `stream_seq` ≠ first frame's `stream_seq`. | Drop; counts a validation strike. | After `MAX_VALIDATION_STRIKES = 3` such mismatches on the same in-progress entry, the entry is evicted and blacklisted to free its per-sender slot. ## Integrity errors | Variant | Trigger | Handle | |-------------------------------|---------------------------------------------------------------------|------------------------------| | `BadMac` | Header SHA-256 integrity tag mismatch (corruption or PSK-holder tampering). | Drop silently. | ## NACK errors | Variant | Trigger | Handle | |-----------------|----------------------------------------------------------|--------| | `NackTooShort` | NACK body shorter than `2 + ⌈total_data/8⌉` bytes. | Drop. | | `BadNackIndex(n)` | A NACK frame's `chunk_index` is non-zero (spec §3.4 requires 0). | Drop. | ## FEC errors | Variant | Trigger | Handle | |-------------|------------------------------------------------------------------|------------------------------| | `Fec(s)` | The Reed-Solomon coder returned an internal error. | Sender bug or memory issue. | ## Resource bounds | Variant | Trigger | Handle | |------------------------|--------------------------------------------------------------------------------|---------------------------------------| | `Blacklisted` | `(from, message_id)` is on the recently-completed blacklist. | Drop; expected for late late frames. | | `PerSenderCap(from)` | New `message_id` from a sender already at `MAX_IN_PROGRESS_PER_SENDER` (= 4). | Drop; rate-limit signal. | ## Builder errors (send time) These are returned by `build_message` / `VoiceSender::send`, not by the assembler, so they affect the local sender rather than an inbound frame. | Variant | Trigger | Handle | |-------------|------------------------------------------------------------------|------------------------------| | `Rng(s)` | The OS random-number generator was unavailable while allocating a `message_id`. | Fail the send; retry later. Should never happen on a healthy host. | --- ## Severity guide for receivers - **Silent drop, expected**: `Blacklisted`, `Duplicate` (returned as the `AssemblyEvent`, not an error), `BadVersion`, `ReservedPacketType`. - **Silent drop, log at debug**: any structural / template / chunk-size error. - **Log at warn**: `BadMac`, `PerSenderCap` — signs of corruption or rate-limit pressure. - **Surface to UI / app**: `UnknownCodec` and `UnsupportedCodec` (the user may want to install or enable a codec); `Rng` (a failed send the user should be told about). → Continue to [Glossary](Glossary.md).