BoundaryML/baml · error · HandleError

{0}

Error message

{0}

What it means

HandleError::InvalidInput(String) is a pass-through variant whose message is the formatted payload itself (`#[error("{0}")]` at handle.rs:24). It is produced by validate_input/validate_media_input when a string argument passed over the FFI boundary contains an embedded NUL byte ('\0'), which C string conventions cannot represent.

Source

Thrown at baml_language/crates/bridge_cffi/src/handle.rs:24

use bridge_ctypes::{CffiHandleTableEntry, HANDLE_TABLE, baml_bridge::cffi::BamlHandleType};

/// An owned handle-table key and its protocol type tag.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct HandleParts {
    pub key: u64,
    pub handle_type: i32,
}

/// Failure from a safe ordinary handle or media operation.
#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
pub enum HandleError {
    #[error("invalid handle")]
    InvalidHandle,
    #[error("handle type mismatch")]
    TypeMismatch,
    #[error("unsupported handle type")]
    UnsupportedHandleType,
    #[error("{0}")]
    InvalidInput(String),
}

fn insert_entry(entry: CffiHandleTableEntry) -> HandleParts {
    let handle_type = entry.handle_type() as i32;
    let key = HANDLE_TABLE.insert(entry);
    HandleParts { key, handle_type }
}

fn validate_input(value: &str, field: &str) -> Result<(), HandleError> {
    if value.contains('\0') {
        return Err(HandleError::InvalidInput(format!(
            "{field} contains an embedded NUL byte"
        )));
    }
    Ok(())
}

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Strip or reject embedded NUL bytes before calling the FFI media constructors.
  2. Find the source of the '\0' (usually a binary buffer converted to a string without sanitization) and fix the producer.
  3. Re-encode media content (e.g. proper base64 without padding/NUL artifacts) before passing it.
  4. If NUL is intentional, pass the data via a length-prefixed channel rather than a C string.

Example fix

// before
let url = std::str::from_utf8(&bytes)?; // may contain '\0'
media_from_url(MediaKind::Generic, url, None)?;
// after
let url = std::str::from_utf8(&bytes)?.trim_end_matches('\0');
if url.contains('\0') { return Err("url contains NUL"); }
media_from_url(MediaKind::Generic, url, None)?;
Defensive patterns

Strategy: validation

Validate before calling

def sanitize_for_ffi(s: str, field: str) -> str:
    if "\0" in s:
        raise ValueError(f"{field} contains an embedded NUL byte")
    return s

Try / catch

try:
    h = bridge.media_from_base64(MediaKind.Generic, b64, None)
except HandleError as e:
    if "NUL" in str(e):
        b64 = b64.replace("\0", "")
        h = bridge.media_from_base64(MediaKind.Generic, b64, None)
    else:
        raise

Prevention

When it happens

Trigger: Calling media_from_url, media_from_file, or media_from_base64 with a url/file/base64 string (or optional mime_type) containing a '\0' character; e.g. base64 blobs or URLs assembled from unchecked user or binary input.

Common situations: Base64 media payloads built from raw bytes including terminators; URLs copied from binary data; MIME types with stray control characters; passing Rust Strings through C-ABI where embedded NULs are illegal.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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