openai/codex · error · anyhow::Error

expected bundle root to be an object

Error message

expected bundle root to be an object

What it means

build_flat_v2_schema flattens the merged JSON Schema bundle for datamodel-code-generator, which only walks one level of definitions. Its first guard requires the bundle root to be a JSON object. The production merge step always returns an object with $schema, title, type, and definitions, so this error means the function received something that step would not produce: a hand-built fixture, a raw sub-schema, or a transformed Value.

Source

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

    Ok(Value::Object(root))
}

/// Build a datamodel-code-generator-friendly v2 bundle from the mixed export.
///
/// 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();

View on GitHub (pinned to 339751715c)

Solutions

  1. Pass a bundle shaped like the merge step output: an object with $schema, title, type object, and definitions keys.
  2. In tests, build the fixture through the real merge path or at minimum wrap it as json!({"definitions": {...}}).
  3. If it fires in a production path, the upstream invariant at the merge step broke; diff recent changes around the bundle construction.

Example fix

// before
let flat = build_flat_v2_schema(&json!([{"definitions": {}}]))?; // array root: error

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

Strategy: type-guard

Validate before calling

// Call-site check before flattening:
if !is_flat_bundle_input(&bundle) {
    return Err(anyhow!("bundle producer must emit an object with a definitions map"));
}

Type guard

fn is_flat_bundle_input(v: &serde_json::Value) -> bool {
    v.as_object().is_some_and(|root| {
        root.get("definitions").is_some_and(serde_json::Value::is_object)
    })
}

Prevention

When it happens

Trigger: Calling build_flat_v2_schema with a Value whose root is an array, string, number, or null: unit-test fixtures crafted with json!, or a refactor that feeds a schemars sub-schema or a definitions array instead of the merged bundle object.

Common situations: Writing tests for the flat-v2 flattening with minimal ad-hoc inputs; refactors of generate_json_with_experimental that change what is passed to the flattener.

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/64606335daf403cc. Report an issue: GitHub.