BoundaryML/baml · error · HandleError
invalid handle
Error message
invalid handle
What it means
HandleError::InvalidHandle from handle.rs. The bridge received a handle value that does not refer to any live object in the handle table — it was never issued, was already closed/freed, or was corrupted at the FFI boundary. Raised for safe ordinary-handle and media operations.
Source
Thrown at baml_language/crates/bridge_cffi/src/handle.rs:18
//! Safe, target-neutral ordinary handle and media operations.
use std::sync::Arc;
use bex_project::{BexExternalAdt, MediaKind, MediaValue};
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!(View on GitHub (pinned to bd85ce9dee)
Solutions
- Re-acquire a fresh handle from the API that originally created it.
- Check the handle was not already closed/released before reuse.
- Ensure the runtime instance that issued the handle is still alive.
- Verify ctypes struct layout matches the Rust definition so the id is not corrupted.
Example fix
# before handle = 0 # zeroed struct default media_read(handle) # after handle = runtime.create_media(path) media_read(handle)
Defensive patterns
Strategy: type-guard
Validate before calling
if handle.id == 0 or handle.id not in issued_handles:
raise ValueError('stale or invalid handle') Type guard
def is_live_handle(handle, issued: set) -> bool:
return handle.id != 0 and handle.id in issued Try / catch
try:
result = bridge.media_read(handle)
except BridgeError as e:
if e is HandleError.InvalidHandle:
handle = reacquire_handle(source)
result = bridge.media_read(handle) Prevention
- Never cache handles beyond the runtime's lifetime
- Close handles exactly once and drop references afterwards
- Verify ctypes struct layouts against the Rust definitions
When it happens
Trigger: Passing a stale or already-released handle to a handle/media API; passing a fabricated or zeroed handle value across ctypes; using a handle after the runtime that owns it was destroyed.
Common situations: Using a handle after runtime shutdown or handle_close; garbage/zero-initialized ctypes structs; holding handles across process boundaries or serializing them.
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
- Invalid handle key: {0}
- handle type mismatch
- unsupported handle type
- Cannot convert to owned: {reason}
- baml.panics.HostContractViolation
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/5445fef4bf60f4b3.
Report an issue: GitHub.