BoundaryML/baml · error · CtypesError

Invalid handle key

Error message

Invalid handle key: {0}

What it means

CtypesError::InvalidHandleKey(u64) indicates a handle-table key passed across the bridge does not resolve to any live entry in HANDLE_TABLE. The key may be stale (already released), from another process, or simply wrong.

Solutions

  1. Keep the handle alive for as long as you use the key; call release_handle exactly once per ownership.
  2. Re-acquire the handle (e.g. media_from_url/... ) if it was released; do not cache keys across sessions.
  3. Log the key and check live_handle_count/refcount instrumentation to confirm it is live.
  4. Search for double-release paths in the host code (release on both success and error paths).

Example fix

// before
release_handle(key);  # ok
release_handle(key);  # InvalidHandleKey / invalid handle
// after
if not released.contains(key):
    release_handle(key)
    released.add(key)
Defensive patterns

Strategy: try-catch

Validate before calling

# check liveness before use (test instrumentation)
assert bridge.live_handle_count() > 0 and key in live_keys

Try / catch

try:
    media = bridge.media_url(key, handle_type)
except BridgeError as e:
    if str(e).startswith("Invalid handle key"):
        media = reacquire_media()  # re-mint the handle
    else:
        raise

Prevention

When it happens

Trigger: Calling clone_handle/release_handle/media_* accessors with a key that was already released, never created, or outlived its table row; using a key from a previous bridge session.

Common situations: Double-free of handles (releasing twice); lifetime bugs where the host dropped a handle but still uses it; serializing keys across process restarts; ID reuse assumptions after upgrades.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

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

//! 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 },

    #[error(
        "Invalid InboundValue.value_type: a root union or optional does not identify one exact selected type"

View on GitHub (pinned to bd85ce9dee)