BoundaryML/baml · error · CtypesError

Null buffer pointer

Error message

Null buffer pointer

What it means

CtypesError::NullBuffer is thrown when an FFI conversion function receives a null pointer where a byte buffer was required. The bridge refuses to dereference null and reports this error instead of crashing.

Source

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

//! 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
    /// hostile descriptor cannot amplify logs by echoing its full payload.
    #[error("Invalid decimal bigint literal ({len} bytes)")]
    InvalidBigintLiteral { len: usize },

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Check the pointer is non-null before calling the bridge; for empty payloads pass a valid (possibly empty) buffer with len 0.
  2. In Python, convert None/empty values explicitly to b"" and pass from a real bytes object.
  3. Audit the FFI shim struct so the buffer field is always initialized.
  4. Add an assertion/log at the call site to catch the null origin.

Example fix

// before
ptr = None
lib.decode_inbound(ptr, 0)  # NullBuffer
// after
buf = b"" if data is None else data
ptr = (ctypes.c_char * len(buf)).from_buffer_copy(buf)
lib.decode_inbound(ptr, len(buf))
Defensive patterns

Strategy: validation

Validate before calling

buf = b"" if data is None else bytes(data)
if ptr is None and len(buf) > 0:
    raise ValueError("buffer pointer is null")

Try / catch

try:
    out = bridge.decode_inbound(ptr, length)
except BridgeError as e:
    if "Null buffer pointer" in str(e):
        out = bridge.decode_inbound(empty_buf, 0)  # or surface a clear host-side error
    else:
        raise

Prevention

When it happens

Trigger: Passing NULL (0) as the data pointer/len pair into bridge encode/decode entry points — e.g. an empty Python bytes converted to a null ctypes pointer, or a failed allocation upstream left the pointer null.

Common situations: ctypes interop in Python where an empty/None value became a null pointer; callers skipping the length=0 shortcut and passing null; uninitialized struct fields in the FFI shim.

Related errors


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