{"record":{"id":"8b9b1fce8454db2d","repo":"BoundaryML/baml","slug":"map-entry-missing-key","errorCode":null,"errorMessage":"Map entry missing key","messagePattern":"Map entry missing key","errorType":"error_code","errorClass":"CtypesError","httpStatus":null,"severity":"error","filePath":"baml_language/crates/bridge_ctypes/src/error.rs","lineNumber":17,"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 },\n\n    #[error(\n        \"Invalid InboundValue.value_type: a root union or optional does not identify one exact selected type\"\n    )]\n    InvalidInboundValueTypeRootUnion,\n","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/baml_language/crates/bridge_ctypes/src/error.rs#L1-L35","documentation":"CtypesError::MapEntryMissingKey is raised during protobuf value decoding when a map entry arrives without its key field populated. The bridge requires both key and value in each map entry to reconstruct the map.","triggerScenarios":"Decoding an InboundValue containing a map whose entries have a value but no key — usually a hand-built protobuf message or a schema mismatch where the key field was omitted or serialized as empty.","commonSituations":"Manually constructed protobuf payloads in tests/tools; older SDK versions serializing maps differently than the bridge expects; a producer bug dropping empty-string keys.","solutions":["Regenerate/upgrade the producer so map entries always set the key field.","Inspect the serialized bytes (decode independently) to find the entry missing its key.","Fix producers that skip empty keys when assembling the map message.","Validate payloads with a round-trip encode/decode before crossing the FFI boundary."],"exampleFix":"// before\nentries.push(MapEntry { value: Some(v), ..Default::default() })  // key omitted\n// after\nentries.push(MapEntry { key: k, value: Some(v), ..Default::default() })","handlingStrategy":"validation","validationCode":"for entry in map_value.entries:\n    if not entry.HasField(\"key\") or entry.key == \"\":\n        raise ValueError(\"map entry missing key before FFI decode\")","typeGuard":null,"tryCatchPattern":"try:\n    val = bridge.decode_inbound(buf, len(buf))\nexcept BridgeError as e:\n    if \"Map entry missing key\" in str(e):\n        raise ValueError(\"producer sent a map entry without a key; fix serializer\") from e\n    raise","preventionTips":["Round-trip encode/decode maps in tests before sending over FFI","Keep map serializers on the same generated-code version as the bridge","Never drop empty keys when assembling map entries"],"tags":["protobuf","decoding","ffi","map"],"backgroundTag":"unexpected-response-shape","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}