{"record":{"id":"908a482bbed28c24","repo":"BoundaryML/baml","slug":"null-buffer-pointer","errorCode":null,"errorMessage":"Null buffer pointer","messagePattern":"Null buffer pointer","errorType":"error_code","errorClass":"CtypesError","httpStatus":null,"severity":"error","filePath":"baml_language/crates/bridge_ctypes/src/error.rs","lineNumber":11,"sourceCode":"//! Error types used by the shared ctypes conversion logic.\n\nuse thiserror::Error;\n\n/// Errors that can occur during value encoding/decoding for the bridge.\n#[derive(Debug, Error)]\npub enum CtypesError {\n    #[error(\"Protobuf decode error: {0}\")]\n    ProtobufDecode(#[from] prost::DecodeError),\n\n    #[error(\"Null buffer pointer\")]\n    NullBuffer,\n\n    #[error(\"Invalid handle key: {0}\")]\n    InvalidHandleKey(u64),\n\n    #[error(\"Map entry missing key\")]\n    MapEntryMissingKey,\n\n    /// Carries only the input length, not the input itself — untrusted hex\n    /// blobs can be up to the FFI decode cap (~67M chars), and embedding\n    /// them in error messages bloats logs and exposes payload contents.\n    #[error(\"Invalid bigint hex string ({len} bytes)\")]\n    InvalidBigint { len: usize },\n\n    /// Carries only the input length for over-cap decimal type literals, so a\n    /// hostile descriptor cannot amplify logs by echoing its full payload.\n    #[error(\"Invalid decimal bigint literal ({len} bytes)\")]\n    InvalidBigintLiteral { len: usize },","sourceCodeStart":1,"sourceCodeEnd":29,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/baml_language/crates/bridge_ctypes/src/error.rs#L1-L29","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the pointer is non-null before calling the bridge; for empty payloads pass a valid (possibly empty) buffer with len 0.","In Python, convert None/empty values explicitly to b\"\" and pass from a real bytes object.","Audit the FFI shim struct so the buffer field is always initialized.","Add an assertion/log at the call site to catch the null origin."],"exampleFix":"// before\nptr = None\nlib.decode_inbound(ptr, 0)  # NullBuffer\n// after\nbuf = b\"\" if data is None else data\nptr = (ctypes.c_char * len(buf)).from_buffer_copy(buf)\nlib.decode_inbound(ptr, len(buf))","handlingStrategy":"validation","validationCode":"buf = b\"\" if data is None else bytes(data)\nif ptr is None and len(buf) > 0:\n    raise ValueError(\"buffer pointer is null\")","typeGuard":null,"tryCatchPattern":"try:\n    out = bridge.decode_inbound(ptr, length)\nexcept BridgeError as e:\n    if \"Null buffer pointer\" in str(e):\n        out = bridge.decode_inbound(empty_buf, 0)  # or surface a clear host-side error\n    else:\n        raise","preventionTips":["In Python ctypes, always build pointers from real bytes objects, never None","Initialize all fields of FFI shim structs","Treat empty payloads as len=0 with a valid (non-null) buffer"],"tags":["ffi","null-pointer","rust","ctypes"],"backgroundTag":"null-argument","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}