Skip to content

Errors

class EncodeError extends Error {}
class DecodeError extends Error { readonly offset: number }
ErrorThrown when
EncodeErrorvalidation failed on the way in, or the schema cannot be encoded
DecodeErrorthe bytes are malformed, or validation failed on the way out

DecodeError.offset is the byte position reached. For a validation failure, it equals the payload length because structural decoding must consume every byte before validation runs.

try {
decode(Person, bytes);
} catch (error) {
if (error instanceof DecodeError) {
console.error(`bad payload at byte ${error.offset}: ${error.message}`);
}
}

To avoid exceptions, use safeDecode. It returns either { success: true, data } or { success: false, error } and wraps values that are not already Error objects.

These are all EncodeError instances thrown when the codec is built. See Rejected Shapes for workarounds.

MessageCause
Records and open objects are not currently supportedz.looseObject, z.record, v.record
Only nullable JSON Schema unions are currently supporteda general or discriminated union
Only nullable JSON Schema type arrays are currently supporteda type array with >1 non-null entry
Arrays require an item schemaan array with no items
Empty enums are unsupportedan enum with no members
Unsupported JSON Schema literala literal that is not string, number, boolean, or null
Unsupported Standard JSON Schema type Xa type with no wire shape
Unsupported Standard JSON Schema nodea non-object node where a schema was expected
Required property "x" has no schemarequired names a property absent from properties
Schemas with different input and output wire shapes require a bidirectional codec and are not yet supporteda default or widening refinement makes the sides differ
Standard Schema provides validation but not structure; pass a Standard JSON Schema implementation as the second argumentValibot, Zod < 4.2, ArkType < 2.1.28
This schema already decodes to null; wrapping it in nullable() would give null two encodingsm.literal(null).nullable(), or a second null marker over one already reachable
This schema already decodes to undefined; wrapping it in optional() would give undefined two encodingsa second presence marker over one already reachable
fingerprinted() needs a codec built from a Standard JSON Schema; compile() returns one, the low-level m API does notfingerprinted(m.object(...))
Fingerprint bytes must be 1, 2, 3 or 4, received Xout-of-range bytes option
<the vendor's own message> — shorn encodes the wire shape; convert rich types
at the edge (README: Dates, BigInt, Map and Set)

shorn preserves the validator’s original reason and appends guidance. This applies to Date, bigint, Map, Set, undefined, NaN, and transforms. See Date, BigInt, Map, Set.

This Standard Schema validates asynchronously; use encodeAsync/decodeAsync with
the Standard Schema. Neither accepts a compiled or fingerprinted codec.

The second sentence clarifies an important limitation: async entry points accept schemas, not compiled or fingerprinted codecs.

MessageCause
Unknown object property "x"an extra property where the vendor left additionalProperties absent — ArkType by default, Valibot’s object and looseObject
validation issues, joined by ; your refinements failed; paths prefixed as field.nested: message

All DecodeError with an offset.

MessageCause
Expected a Uint8Array, received Xwrong input type; offset 0
Unexpected trailing databytes remained after a complete value
Payload was written by a different schema (expected fingerprint XXXXXX)the schema changed
out-of-bounds readtruncated payload
non-canonical varintoverlong, e.g. [129, 0] for 1
unsafe integera varint beyond the safe integer range
invalid UTF-8decoding is fatal, not replacing
invalid booleana byte other than 0 or 1
invalid enum indexpast the last member
element count exceeds remaining inputa count the payload cannot satisfy

Handle fingerprint mismatches explicitly in production. In the mismatch test, decoding without a fingerprint produced a wrong value without an error about 27% of the time. See Schema Evolution.

A schema nested about 5,900 levels deep can overflow the JavaScript stack and throw RangeError instead of DecodeError. This requires a hostile schema, not only hostile bytes. Limit schema depth if schemas come from untrusted input. See Hostile Input.