BigPizzaV3/CodexPlusPlus · error

model_metadata JSON 解析失败:

Error message

model_metadata JSON 解析失败:{error}

What it means

parse_model_metadata_map parses the profile's model_metadata field into serde_json::Map<String, Value>. On serde_json failure it throws "model_metadata JSON 解析失败:{error}". Empty strings yield an empty map, so only non-empty malformed JSON triggers the error. Called from apply_model_catalog_to_config and normalize_relay_profile_for_storage.

Solutions

  1. Fix the JSON syntax reported in the error detail (line/column from serde_json).
  2. Ensure the shape is {"<model-slug>": {...}, ...} with double-quoted keys and valid JSON values.
  3. Validate with JSON.parse/serde_json before saving; or clear the field to skip metadata overrides.
  4. Generate the JSON programmatically instead of hand-editing.

Example fix

// before
model_metadata = "{deepseek-v4-pro: {context_window: 1000000}}"
// after
model_metadata = "{\"deepseek-v4-pro\": {\"context_window\": 1000000}}"
Defensive patterns

Strategy: validation

Validate before calling

fn metadata_json_is_valid(json: &str) -> bool {
    if json.trim().is_empty() { return true; }
    serde_json::from_str::<serde_json::Value>(json)
        .map(|v| v.is_object())
        .unwrap_or(false)
}

Type guard

fn is_metadata_map(v: &serde_json::Value) -> bool {
    v.as_object().map(|m| m.values().all(|x| x.is_object())).unwrap_or(false)
}

Try / catch

match apply_model_catalog_to_config(...) {
    Err(e) if e.to_string().contains("model_metadata JSON 解析失败") => {
        // surface serde_json's line/column and reject the save in the UI
    }
    other => other?,
}

Prevention

When it happens

Trigger: Applying/saving a profile whose model_metadata is non-empty but invalid JSON — e.g. missing quotes around keys, trailing commas, or pasted JavaScript object literal text.

Common situations: Hand-writing metadata in a UI field with JS syntax ({slug: {...}}), comments in JSON, or truncation when copy-pasting large metadata blobs.

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/882f69f8f615acb4. Report an issue: GitHub.

Appendix: source

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

    }
    Ok(())
}

fn validate_model_auto_compact(model_auto_compact: &HashMap<String, String>) -> anyhow::Result<()> {
    for (slug, value) in model_auto_compact {
        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))
}

View on GitHub (pinned to b1ed92e5e4)