BigPizzaV3/CodexPlusPlus · error

model_metadata 的模型 值必须是对象

Error message

model_metadata 的模型 {slug} 值必须是对象

What it means

parse_model_metadata_map parses the model_metadata JSON string and requires both the top level and every per-model value to be a JSON object. If a slug maps to a non-object (string, number, array, bool, null), the apply fails so malformed model metadata is never written into the catalog/config.

Solutions

  1. Make every value in the model_metadata JSON a proper object, e.g. {"model-a": {"priority": 2}}
  2. Validate the JSON with jq or a linter before applying
  3. Remove the malformed slug entry if its metadata is unnecessary
  4. If migrating from an older format, wrap scalar values in an object with the appropriate field name

Example fix

// before
{"model-a": "enabled"}
// after
{"model-a": {"supports_search_tool": true}}
Defensive patterns

Strategy: validation

Validate before calling

const map = JSON.parse(profile.model_metadata);
if (typeof map !== 'object' || map === null || Array.isArray(map)) throw new Error('model_metadata must be a JSON object');
for (const [slug, v] of Object.entries(map)) {
  if (typeof v !== 'object' || v === null || Array.isArray(v)) throw new Error(`metadata for ${slug} must be an object`);
}

Type guard

const isMetadataObject = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);

Try / catch

try { applyProfile(profile); } catch (e) { if (String(e).includes('model_metadata')) { profile.model_metadata = sanitizeMetadata(profile.model_metadata); applyProfile(profile); } else throw e; }

Prevention

When it happens

Trigger: Calling a config-apply path with profile.model_metadata set to JSON like {"model-a": "enabled"} or {"model-a": [1,2]} — any slug whose value is not a JSON object.

Common situations: Hand-editing model_metadata and using a string instead of an object for a model; an older config format stored per-model scalars; a copy/paste dropped the object braces around the metadata fields.

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 BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19). Data as JSON: /api/errors/375c888f1cb1b547. Report an issue: GitHub.

Appendix: source

Thrown at crates/codex-plus-core/src/relay_config.rs:2147

        if crate::model_suffix::parse_compact_percent(value).is_none() {
            anyhow::bail!("model_auto_compact 的模型 {slug} 百分比无效:{value}");
        }
    }
    Ok(())
}

fn parse_model_metadata_map(metadata_json: &str) -> anyhow::Result<serde_json::Map<String, Value>> {
    if metadata_json.trim().is_empty() {
        return Ok(serde_json::Map::new());
    }
    let value: Value = serde_json::from_str(metadata_json)
        .map_err(|error| anyhow::anyhow!("model_metadata JSON 解析失败:{error}"))?;
    let map = value
        .as_object()
        .ok_or_else(|| anyhow::anyhow!("model_metadata 必须是 JSON 对象"))?;
    for (slug, metadata) in map {
        if !metadata.is_object() {
            anyhow::bail!("model_metadata 的模型 {slug} 值必须是对象");
        }
    }
    Ok(map.clone())
}

fn model_metadata_has_entries(
    metadata: &serde_json::Map<String, Value>,
    entry_slugs: &HashSet<String>,
) -> bool {
    metadata.keys().any(|slug| entry_slugs.contains(slug))
}

fn apply_model_metadata_overrides(
    catalog_json: &str,
    override_map: &serde_json::Map<String, Value>,
) -> anyhow::Result<String> {
    if override_map.is_empty() {
        return Ok(catalog_json.to_string());

View on GitHub (pinned to b1ed92e5e4)