Error Reference
wirespec errors fall into two categories: runtime error codes returned by generated C functions, and compiler errors emitted during compilation.
Runtime Error Codes
All generated parse and serialize functions return wirespec_result_t. The value is one of:
| Code | Value | Meaning |
|---|---|---|
WIRESPEC_OK | 0 | Success. |
WIRESPEC_ERR_SHORT_BUFFER | 1 | Not enough bytes remain in the input buffer (parse) or output buffer (serialize). |
WIRESPEC_ERR_INVALID_TAG | 2 | The tag value does not match any known pattern in a frame or capsule. |
WIRESPEC_ERR_CONSTRAINT | 3 | A require expression evaluated to false. |
WIRESPEC_ERR_OVERFLOW | 4 | An integer overflow occurred — e.g., a VarInt value exceeds the target type range, or a length value exceeds SIZE_MAX. |
WIRESPEC_ERR_INVALID_STATE | 5 | A state machine received an event for which no matching transition exists. |
WIRESPEC_ERR_TRAILING_DATA | 6 | A within EXPR scope was not fully consumed — bytes remain after the inner parse completed. |
WIRESPEC_ERR_NONCANONICAL | 7 | An @strict type was encoded in non-canonical (non-minimum-length) form. |
WIRESPEC_ERR_UNSUPPORTED | 8 | The input requests a feature that the generated code does not support. |
WIRESPEC_ERR_CAPACITY | 9 | A parsed array element count exceeds the field's allocated capacity (WIRESPEC_MAX_ARRAY_ELEMENTS or @max_len). |
WIRESPEC_ERR_CHECKSUM | 10 | Checksum verification failed during parse. |
WIRESPEC_ERR_SCOPE_UNDERFLOW | 11 | Sub-cursor underflow — an internal scope boundary was violated. |
WIRESPEC_ERR_ARRAY_OVERFLOW | 12 | Array index out of bounds during parsing. |
These codes are defined in wirespec_runtime.h:
typedef enum {
WIRESPEC_OK = 0,
WIRESPEC_ERR_SHORT_BUFFER = 1,
WIRESPEC_ERR_INVALID_TAG = 2,
WIRESPEC_ERR_CONSTRAINT = 3,
WIRESPEC_ERR_OVERFLOW = 4,
WIRESPEC_ERR_INVALID_STATE = 5,
WIRESPEC_ERR_TRAILING_DATA = 6,
WIRESPEC_ERR_NONCANONICAL = 7,
WIRESPEC_ERR_UNSUPPORTED = 8,
WIRESPEC_ERR_CAPACITY = 9,
WIRESPEC_ERR_CHECKSUM = 10,
WIRESPEC_ERR_SCOPE_UNDERFLOW = 11,
WIRESPEC_ERR_ARRAY_OVERFLOW = 12,
} wirespec_result_t;Error Handling Pattern
wirespec_result_t rc = quic_frames_quic_frame_parse(buf, len, &frame, &consumed);
switch (rc) {
case WIRESPEC_OK:
break;
case WIRESPEC_ERR_SHORT_BUFFER:
/* Need more data — wait for more bytes or report truncated input */
break;
case WIRESPEC_ERR_INVALID_TAG:
/* Unknown frame type — discard or log */
break;
case WIRESPEC_ERR_CONSTRAINT:
/* Protocol constraint violated — close connection */
break;
case WIRESPEC_ERR_CHECKSUM:
/* Corrupted packet — discard */
break;
default:
/* Unexpected error */
break;
}Error Code Notes
WIRESPEC_ERR_SHORT_BUFFER is the most common error during incremental parsing. Callers that accumulate data in a ring buffer should retry with more data when this code is returned.
WIRESPEC_ERR_INVALID_TAG is returned only when no _ wildcard branch is present in the frame or capsule. Adding _ => Unknown { data: bytes[remaining] } causes unknown tags to be captured rather than rejected.
WIRESPEC_ERR_NONCANONICAL is returned only for types annotated with @strict. Without @strict, all encodings that decode to a valid value are accepted.
WIRESPEC_ERR_TRAILING_DATA indicates a length-prefixed scope (within EXPR) whose declared length was not fully consumed by the inner parse. This usually indicates a malformed packet or a newer protocol version with additional fields.
WIRESPEC_ERR_UNSUPPORTED indicates the input requests a feature or variant that the generated code does not handle.
WIRESPEC_ERR_CAPACITY does not indicate a protocol error — it indicates that the generated code's statically-allocated array is too small. Increase capacity with -DWIRESPEC_MAX_ARRAY_ELEMENTS=N or @max_len(N) on the field.
WIRESPEC_ERR_SCOPE_UNDERFLOW is an internal error indicating that a sub-cursor's scope boundary was violated. This typically indicates a bug in the protocol definition or an internal error in the generated code.
WIRESPEC_ERR_ARRAY_OVERFLOW indicates that an array index went out of bounds during parsing. This is a safety check in the generated code.
Compiler Errors
The wirespec compiler reports errors with source file path, line and column, a source line excerpt, a ^^^^^ pointer, context information, and optional hint text.
Error Display Format
error: undefined type 'Varnt'
--> file.wspec:2:7
|
2 | x: Varnt,
| ^^^^^
= in packet 'Foo'
hint: did you mean 'VarInt'?Fields in the display:
| Field | Description |
|---|---|
error: | Error message |
--> | File path, line number, column number |
| Source line | The line of source text containing the error |
^^^^^ pointer | Underlines the offending token(s) |
= in ... | Context — the enclosing definition |
hint: | Optional hint, including similarity-based suggestions |
Common Compile-Time Errors
Undefined type or field:
error: undefined type 'AckRng'
--> examples/quic/frames.wspec:12:15
|
12 | gap: AckRng,
| ^^^^^^
= in packet 'AckRange'
hint: did you mean 'AckRange'?Caused by a typo in a type name or missing import. The compiler uses Levenshtein distance to suggest the closest known name.
Forward field reference:
error: field 'length' is used before it is declared
--> examples/quic/frames.wspec:8:28Fields are only visible to subsequent fields in the same scope. A field cannot reference one declared later in the same packet, frame branch, or capsule.
Non-integer-like type as length or count:
error: 'bytes[length: x]' requires an integer-like type; got 'bool'The expressions in bytes[length: EXPR], bytes[length_or_remaining: EXPR], [T; EXPR], and within EXPR must resolve to an integer-like type (u8, u16, u32, u64, VarInt, or similar).
remaining or fill not at end of scope:
error: 'bytes[remaining]' must be the last wire field in its scope
--> examples/quic/frames.wspec:22:5bytes[remaining] and [T; fill] consume all remaining bytes/elements in the current scope. No further wire fields may follow them (though let bindings and require clauses may).
Circular import:
error: circular import detected: a -> b -> c -> awirespec does not support circular imports. Refactor shared types into a common dependency module.
Missing field initialization in state machine action:
error: field 'dst.challenge' has no default value and is not assigned in action
--> examples/mpquic/path.wspec:18:5Every field in the destination state that lacks a default value must be explicitly assigned in the action block. Fields with = default_value in the state declaration can be omitted.
Shadowing a reserved identifier:
error: 'remaining' is a reserved keyword and cannot be used as a field nameThe identifiers bool, null, fill, remaining, in_state, all, child_state_changed, src, and dst have special meaning and cannot be used as user-defined names.
Multiple @checksum annotations:
error: at most one @checksum annotation is allowed per packet/frame branch@checksum field type mismatch:
error: @checksum(internet) requires field type u16; got u32Similarity Suggestions
When an undefined name is used, the compiler computes the Levenshtein distance between the unknown name and all names in scope. If a close match is found, it is shown as a hint: suggestion. This covers type names, field names, and module paths in import statements.
Context Stacks
For errors that occur inside nested constructs (e.g., inside a frame branch or inside a capsule payload), the compiler emits context information showing the enclosing definition:
error: type mismatch ...
--> examples/quic/frames.wspec:45:20
|
= in field 'data' in frame branch 'Stream'
= in frame 'QuicFrame'