openai/codex · error · anyhow::Error

expected bundle definitions map

Error message

expected bundle definitions map

What it means

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.

Source

Thrown at codex-rs/app-server-protocol/src/export.rs:1096

///
/// The full bundle keeps v2 schemas nested under `definitions.v2`, plus a few
/// shared root definitions like `ClientRequest` and `ServerNotification`.
/// Python codegen only walks one definitions map level, so
/// a direct feed would treat `v2` itself as a schema and miss unreferenced v2
/// leaves. This helper flattens all v2 definitions to the root definitions map,
/// then pulls in the shared root schemas and any non-v2 transitive deps they
/// still reference. Keep the shared root unions intact here: some valid
/// request/notification/event variants are inline or only reference shared root
/// helpers, so filtering them by the presence of a `#/definitions/v2/` ref
/// would silently drop real API surface from the flat bundle.
fn build_flat_v2_schema(bundle: &Value) -> Result<Value> {
    let Value::Object(root) = bundle else {
        return Err(anyhow!("expected bundle root to be an object"));
    };
    let definitions = root
        .get("definitions")
        .and_then(Value::as_object)
        .ok_or_else(|| anyhow!("expected bundle definitions map"))?;
    let v2_definitions = definitions
        .get("v2")
        .and_then(Value::as_object)
        .ok_or_else(|| anyhow!("expected v2 namespace in bundle definitions"))?;

    let mut flat_root = root.clone();
    let title = root
        .get("title")
        .and_then(Value::as_str)
        .unwrap_or("CodexAppServerProtocol");
    let mut flat_definitions = v2_definitions.clone();
    let mut shared_definitions = Map::new();
    let mut non_v2_refs = HashSet::new();

    for shared in FLAT_V2_SHARED_DEFINITIONS {
        let Some(shared_schema) = definitions.get(*shared) else {
            continue;
        };

View on GitHub (pinned to 339751715c)

Solutions

  1. Include an object definitions map in the bundle; add the v2 namespace too or the next guard fires.
  2. Produce fixtures via the real merge path so required keys are always present.
  3. If hit outside tests, check that the producer still inserts definitions at the merge step and that nothing renamed the key.

Example fix

// before
let flat = build_flat_v2_schema(&json!({"title": "CodexAppServerProtocol"}))?; // no definitions

// after
let flat = build_flat_v2_schema(&json!({
    "title": "CodexAppServerProtocol",
    "definitions": {"v2": {}}
}))?;
Defensive patterns

Strategy: type-guard

Validate before calling

// Call-site check before flattening:
if !has_definitions_map(&bundle) {
    return Err(anyhow!("bundle must carry an object definitions map"));
}

Type guard

fn has_definitions_map(v: &serde_json::Value) -> bool {
    v.get("definitions").is_some_and(serde_json::Value::is_object)
}

Prevention

When it happens

Trigger: 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.

Common situations: Test bundles trimmed to the minimum; key-name drift between the producer and the flattener after refactoring the export pipeline.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of openai/codex@339751715c (2026-08-25). Data as JSON: /api/errors/dad638ed92958933. Report an issue: GitHub.