Handling errors

If a message arrives incomplete, decode() cannot read it:

from bytespec import DecodeError, ProtoModel

class Message(ProtoModel):
    text: str

encoded = Message(text="Hello").encode()
try:
    Message.decode(encoded[:-1])
except DecodeError:
    print("The message is truncated or does not match the model")
The message is truncated or does not match the model

Catch DecodeError where the application receives and decodes external messages. This error also covers invalid text, unknown enum values, and other data that does not fit the model.

A value does not fit in a field

from bytespec import EncodeError
from bytespec.types import UInt8

class Packet(ProtoModel):
    number: UInt8

packet = Packet(number=256)
try:
    packet.encode()
except EncodeError as error:
    print(error)
Packet.number: UInt8Codec (B): cannot encode 256

UInt8 only allows numbers up to 255. The instance was created, but encoding failed. A string too long for the chosen prefix and text that cannot be represented in the selected encoding are handled similarly.

Model annotations define the format but do not fully validate explicitly supplied constructor arguments. Pass values of the appropriate types; do not expect "42" to be converted to a number or a dictionary to a model.

An error in a model declaration

Invalid settings are detected when the class is created:

from bytespec import SchemaError

try:
    class User(ProtoModel):
        email: str | None  # an optional field needs field(flag=...)
except SchemaError:
    print("Add a flag number for email")
Add a flag number for email

SchemaError also occurs for unsupported annotations, duplicate indices, or invalid length prefixes.

Which exceptions to catch

Exception

Meaning

SchemaError

The declared types or settings cannot be used

EncodeError

The value cannot be encoded in the chosen representation

DecodeError

The message cannot be decoded using this model

BytespecError

The common base class for the three errors above

All four classes are imported from bytespec. If you handle all library errors in the same way, you can catch BytespecError. See Exceptions for the full hierarchy and the cases that raise each exception.

Python call errors remain ordinary exceptions. For example, Message() without the required text raises TypeError. Errors in custom codec implementations are not automatically wrapped either. Exceptions from __validate__ also propagate unchanged, including when called through decode(); handle the application’s chosen exception type separately (see Validating model values). For header checks and their current limitations, see What is checked in 0.1.0.

A field error message includes the model and field names; for wrapped errors, the original cause is available through error.__cause__. For diagnostics, you can print the full exception, as in the second example. Do not treat its text as a machine-readable protocol: separate field and offset attributes are not provided.

This concludes the basic guide. Continue with Files and multiple messages to work with files or multiple messages, Codecs: custom formats and types for custom types, or Binary / wire format to agree on a binary format with another party.