{"record":{"id":"dad638ed92958933","repo":"openai/codex","slug":"expected-bundle-definitions-map","errorCode":null,"errorMessage":"expected bundle definitions map","messagePattern":"expected bundle definitions map","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"codex-rs/app-server-protocol/src/export.rs","lineNumber":1096,"sourceCode":"///\n/// The full bundle keeps v2 schemas nested under `definitions.v2`, plus a few\n/// shared root definitions like `ClientRequest` and `ServerNotification`.\n/// Python codegen only walks one definitions map level, so\n/// a direct feed would treat `v2` itself as a schema and miss unreferenced v2\n/// leaves. This helper flattens all v2 definitions to the root definitions map,\n/// then pulls in the shared root schemas and any non-v2 transitive deps they\n/// still reference. Keep the shared root unions intact here: some valid\n/// request/notification/event variants are inline or only reference shared root\n/// helpers, so filtering them by the presence of a `#/definitions/v2/` ref\n/// would silently drop real API surface from the flat bundle.\nfn build_flat_v2_schema(bundle: &Value) -> Result<Value> {\n    let Value::Object(root) = bundle else {\n        return Err(anyhow!(\"expected bundle root to be an object\"));\n    };\n    let definitions = root\n        .get(\"definitions\")\n        .and_then(Value::as_object)\n        .ok_or_else(|| anyhow!(\"expected bundle definitions map\"))?;\n    let v2_definitions = definitions\n        .get(\"v2\")\n        .and_then(Value::as_object)\n        .ok_or_else(|| anyhow!(\"expected v2 namespace in bundle definitions\"))?;\n\n    let mut flat_root = root.clone();\n    let title = root\n        .get(\"title\")\n        .and_then(Value::as_str)\n        .unwrap_or(\"CodexAppServerProtocol\");\n    let mut flat_definitions = v2_definitions.clone();\n    let mut shared_definitions = Map::new();\n    let mut non_v2_refs = HashSet::new();\n\n    for shared in FLAT_V2_SHARED_DEFINITIONS {\n        let Some(shared_schema) = definitions.get(*shared) else {\n            continue;\n        };","sourceCodeStart":1078,"sourceCodeEnd":1114,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/app-server-protocol/src/export.rs#L1078-L1114","documentation":"Second guard in build_flat_v2_schema: after the root object check it requires root[\"definitions\"] to exist and be an object, because the flattening walks that map. The merge step always inserts a definitions object, so a missing or non-object map means the input was not produced by that step: fixtures that omit the key, or refactors that renamed or dropped it.","triggerScenarios":"Calling build_flat_v2_schema with a bundle whose definitions key is absent, null, or an array: minimal test fixtures that include only the keys under assertion, or a renamed definitions key after a schema-shape refactor.","commonSituations":"Test bundles trimmed to the minimum; key-name drift between the producer and the flattener after refactoring the export pipeline.","solutions":["Include an object definitions map in the bundle; add the v2 namespace too or the next guard fires.","Produce fixtures via the real merge path so required keys are always present.","If hit outside tests, check that the producer still inserts definitions at the merge step and that nothing renamed the key."],"exampleFix":"// before\nlet flat = build_flat_v2_schema(&json!({\"title\": \"CodexAppServerProtocol\"}))?; // no definitions\n\n// after\nlet flat = build_flat_v2_schema(&json!({\n    \"title\": \"CodexAppServerProtocol\",\n    \"definitions\": {\"v2\": {}}\n}))?;","handlingStrategy":"type-guard","validationCode":"// Call-site check before flattening:\nif !has_definitions_map(&bundle) {\n    return Err(anyhow!(\"bundle must carry an object definitions map\"));\n}","typeGuard":"fn has_definitions_map(v: &serde_json::Value) -> bool {\n    v.get(\"definitions\").is_some_and(serde_json::Value::is_object)\n}","tryCatchPattern":null,"preventionTips":["Derive test bundles from the real export path so the definitions key is always present.","When renaming schema keys, update producers and consumers (this flattener) in the same change.","Fix the producer when this fires; do not catch and default."],"tags":["json-schema","codegen","invariant","export","schema-bundle"],"backgroundTag":"schema-validation-failed","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}