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
- Fix the JSON syntax reported in the error detail (line/column from serde_json).
- Ensure the shape is {"<model-slug>": {...}, ...} with double-quoted keys and valid JSON values.
- Validate with JSON.parse/serde_json before saving; or clear the field to skip metadata overrides.
- 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
- Generate model_metadata JSON programmatically, not by hand
- Validate with JSON.parse/serde_json on input
- Leave the field empty when no metadata overrides are needed
- Avoid JS object-literal syntax (unquoted keys, comments) in the field
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)