BigPizzaV3/CodexPlusPlus · error

catalog JSON 解析失败:

Error message

catalog JSON 解析失败:{error}

What it means

apply_model_metadata_overrides parses the generated (or provided) catalog JSON before merging per-model metadata overrides. If the catalog string is not valid JSON, it throws "catalog JSON 解析失败:{error}". An empty override_map short-circuits and returns the catalog unchanged, so this only fires when overrides exist and the catalog itself is corrupt.

Solutions

  1. Fix the JSON syntax at the position reported in the error detail inside the catalog string/file.
  2. Regenerate the catalog from the model_list suffix syntax (deepseek-v4-pro[1M]) instead of hand-editing.
  3. Refetch the upstream catalog JSON if it was cached corrupted.
  4. Verify the catalog parses with serde_json/JSON.parse before passing it into the apply flow.

Example fix

// before (catalog.json)
{"models": [{"slug": "a"}, {"slug": "b"} // trailing comment
// after (catalog.json)
{"models": [{"slug": "a"}, {"slug": "b"}]}
Defensive patterns

Strategy: validation

Validate before calling

fn catalog_json_is_valid(catalog: &str) -> bool {
    serde_json::from_str::<serde_json::Value>(catalog)
        .map(|v| v.get("models").and_then(|m| m.as_array()).is_some())
        .unwrap_or(false)
}

Try / catch

match apply_model_metadata_overrides(catalog, overrides) {
    Err(e) if e.to_string().contains("catalog JSON 解析失败") => {
        // regenerate the catalog from model_list instead of using the corrupt string
    }
    other => other?,
}

Prevention

When it happens

Trigger: Applying a model catalog where the stored catalog_json (from model_suffix parsing or a fetched /models catalog) is malformed — truncated file, concatenated JSON, or hand-edited catalog content.

Common situations: Manually editing a generated catalog file and breaking syntax, a fetch/cache step writing partial JSON, or passing raw text (not JSON) as catalog_json.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19). Data as JSON: /api/errors/897d73bed4b1bd25. Report an issue: GitHub.

Appendix: source

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

    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());
    }
    let mut catalog: Value = serde_json::from_str(catalog_json)
        .map_err(|error| anyhow::anyhow!("catalog JSON 解析失败:{error}"))?;
    let Some(models) = catalog.get_mut("models").and_then(Value::as_array_mut) else {
        return Ok(catalog_json.to_string());
    };
    for model in models {
        let Some(slug) = model.get("slug").and_then(Value::as_str) else {
            continue;
        };
        let Some(user_override) = override_map.get(slug).and_then(Value::as_object) else {
            continue;
        };
        let Some(model_object) = model.as_object_mut() else {
            continue;
        };
        for (key, value) in user_override {
            // 窗口与压缩阈值由 model_windows / model_auto_compact 生成(issue #2191);
            // max_context_window 是 codex 运行时的 clamp 权威,绝不能被历史 metadata 残留值覆盖。
            if matches!(
                key.as_str(),

View on GitHub (pinned to b1ed92e5e4)