BoundaryML/baml · error

Value is null for key {}

Error message

Value is null for key {}

What it means

Thrown by from_host_kv_to_baml_kv after the key has been resolved, when the HostMapEntry's `value` field is None. A key/value pair must carry both parts; a present key with a null value cannot be represented as a BamlValue, so the decode bails with the offending key name in the message.

Source

Thrown at engine/language_client_cffi/src/ctypes/baml_value_decode.rs:63

    }
}

pub(super) fn from_host_kv_to_baml_kv(
    item: crate::baml::cffi::HostMapEntry,
) -> Result<(String, BamlValue), anyhow::Error> {
    use crate::baml::cffi::host_map_entry::Key;
    let key = match item.key {
        Some(Key::StringKey(key)) => key,
        Some(Key::EnumKey(key)) => key.value,
        Some(Key::IntKey(_)) | Some(Key::BoolKey(_)) => {
            anyhow::bail!("only string keys are supported")
        }
        None => anyhow::bail!("Key is missing"),
    };

    let value = item
        .value
        .ok_or(anyhow::anyhow!("Value is null for key {}", key))?;

    Ok((key, BamlValue::decode(value)?))
}

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Ensure every argument/tag entry has its value set before crossing the FFI boundary; represent nulls as an explicit BamlValue::Null rather than an unset field
  2. Upgrade the host SDK/bindings to match the engine version so optional-value serialization is consistent
  3. Validate the kwargs/tags map host-side and drop or fill entries with missing values before calling the BAML function

Example fix

// before (host side)
kwargs = {"model": None}  // value field left unset

// after
kwargs = {"model": client.baml_options.null_value}  // explicit null BamlValue
Defensive patterns

Strategy: validation

Validate before calling

# host side
missing = [k for k, v in kwargs.items() if v is _unset_sentinel]
if missing:
    raise ValueError(f"Arguments with no encoded value: {missing}")

Type guard

def all_values_set(entries: dict) -> bool:
    return all(v is not _unset_sentinel for v in entries.values())

Try / catch

try:
    result = client.CallFunction(fn, kwargs)
except Exception as e:
    if "Value is null for key" in str(e):
        raise ValueError(f"Pass an explicit BAML null instead of an unset value for: {e}") from e
    raise

Prevention

When it happens

Trigger: A host caller passes a map entry whose value was not set (protobuf oneof/value absent), e.g. function arguments, tags, or kwargs where one parameter was declared but given no value.

Common situations: Passing None/null parameter values through the CFFI without wrapping them as an explicit BAML null, binding/runtime version skew, or builders that add keys before assigning values.

Related errors


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