BoundaryML/baml · error · CtypesError

Protobuf decode error: {0}

Error message

Protobuf decode error: {0}

What it means

CtypesError::ProtobufDecode wraps a prost::DecodeError raised while decoding a protobuf-encoded message crossing the bridge FFI boundary. It means the byte buffer handed to the ctypes conversion layer was not valid protobuf for the expected message type (corrupt, truncated, or produced by an incompatible schema).

Source

Thrown at baml_language/crates/bridge_ctypes/src/error.rs:8

//! Error types used by the shared ctypes conversion logic.

use thiserror::Error;

/// Errors that can occur during value encoding/decoding for the bridge.
#[derive(Debug, Error)]
pub enum CtypesError {
    #[error("Protobuf decode error: {0}")]
    ProtobufDecode(#[from] prost::DecodeError),

    #[error("Null buffer pointer")]
    NullBuffer,

    #[error("Invalid handle key: {0}")]
    InvalidHandleKey(u64),

    #[error("Map entry missing key")]
    MapEntryMissingKey,

    /// Carries only the input length, not the input itself — untrusted hex
    /// blobs can be up to the FFI decode cap (~67M chars), and embedding
    /// them in error messages bloats logs and exposes payload contents.
    #[error("Invalid bigint hex string ({len} bytes)")]
    InvalidBigint { len: usize },

    /// Carries only the input length for over-cap decimal type literals, so a

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Ensure the caller encodes with the same protobuf schema version the bridge was built with; rebuild/realign both sides.
  2. Verify the buffer length and contents before the call (decode the bytes independently with prost to see the underlying error).
  3. Check that the full serialized message, not a truncated slice, is passed.
  4. Regenerate the protobuf bindings if the schema was updated.

Example fix

// before
let val = bridge::decode_inbound(&buf[..len-1])?; // truncated -> ProtobufDecode
// after
let val = bridge::decode_inbound(&buf)?;
Defensive patterns

Strategy: validation

Validate before calling

import google.protobuf
# Independently decode before crossing the FFI boundary:
msg.ParseFromString(buf)  # raises DecodeError early with a clear cause
assert msg.IsInitialized()

Try / catch

try:
    result = bridge.decode(buf, len(buf))
except BridgeError as e:
    if "Protobuf decode error" in str(e):
        raise ValueError(f"payload not valid protobuf (len={len(buf)})") from e
    raise

Prevention

When it happens

Trigger: Calling bridge functions that accept encoded InboundValue/descriptor buffers when the bytes fail prost decoding — wrong message type, truncated buffer, mismatched protobuf schema versions between host and library.

Common situations: Version skew between a client SDK and the native bridge library (schema changed); buffers truncated to an FFI length cap; passing raw (non-protobuf) bytes; endianness/copy bugs in the caller's marshalling code.

Understand the failure class

Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.

Related errors


AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12). Data as JSON: /api/errors/f37002a7e948ccbb. Report an issue: GitHub.