BigPizzaV3/CodexPlusPlus · error
JSON 解析失败:
Error message
{field_name} JSON 解析失败:{error} What it means
parse_model_string_map(field_name, value) parses a JSON-string field of a RelayProfile (e.g. model windows/env maps) into HashMap<String,String>. If serde_json::from_str fails, the error is re-wrapped as "{field_name} JSON 解析失败:{error}" naming the field. Empty/whitespace strings are treated as an empty map, so only non-empty malformed JSON triggers this.
Solutions
- Fix the JSON in the named field: it must be an object like {"model-slug": "1000000"} with double quotes and no trailing commas.
- Validate the field text with a JSON parser (JSON.parse / serde_json) before saving the profile.
- If unsure, clear the field (leave empty) — empty string is accepted and means 'no entries'.
- Use the [1M]-suffix model_list syntax instead of hand-writing the JSON map when declaring context windows.
Example fix
// before
model_windows = "deepseek-v4-pro: 1000000"
// after
model_windows = "{\"deepseek-v4-pro\": \"1000000\"}" Defensive patterns
Strategy: validation
Validate before calling
fn is_valid_string_map(json: &str) -> bool {
if json.trim().is_empty() { return true; }
serde_json::from_str::<serde_json::Map<String, serde_json::Value>>(json)
.ok()
.map(|m| m.values().all(|v| v.is_string()))
.unwrap_or(false)
} Type guard
fn as_string_map(v: &serde_json::Value) -> Option<HashMap<String, String>> {
v.as_object().map(|o| o.iter()
.filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), s.to_string())))
.collect())
} Try / catch
match normalize_relay_profile_for_storage(profile) {
Err(e) if e.to_string().contains("JSON 解析失败") => {
// highlight the offending field in the UI and refuse to save
}
other => other?,
} Prevention
- Validate JSON fields in the UI on blur before saving a profile
- Use double quotes only; no comments or trailing commas
- Leave map fields empty when unsure — empty string is accepted
- Prefer the model_list [1M] suffix syntax over hand-written JSON maps
When it happens
Trigger: Saving or applying a profile where a JSON-map field contains invalid JSON — e.g. model_windows set to `"deepseek: 1000000"` (missing braces/quotes) or trailing commas — via normalize_relay_profile_for_storage or the apply pipeline.
Common situations: Users typing YAML/INI-style text instead of JSON into UI textarea fields, single quotes instead of double quotes, trailing commas, or pasting JSON5/with comments.
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/0e8effa11750f281.
Report an issue: GitHub.
Appendix: source
Thrown at crates/codex-plus-core/src/relay_config.rs:2103
custom_responses.then_some(false),
official_deepseek_responses,
);
let catalog_json = apply_model_metadata_overrides(&catalog_json, &model_metadata)?;
crate::settings::atomic_write(&catalog_path, catalog_json.as_bytes())?;
let mut doc = parse_toml_document(&config_text)?;
doc["model_catalog_json"] = toml_edit::value(catalog_relative);
Ok(normalize_optional_toml(doc))
}
fn parse_model_string_map(
value: &str,
field_name: &str,
) -> anyhow::Result<HashMap<String, String>> {
if value.trim().is_empty() {
return Ok(HashMap::new());
}
let parsed: Value = serde_json::from_str(value)
.map_err(|error| anyhow::anyhow!("{field_name} JSON 解析失败:{error}"))?;
let object = parsed
.as_object()
.ok_or_else(|| anyhow::anyhow!("{field_name} 必须是 JSON 对象"))?;
object
.iter()
.map(|(key, value)| {
let value = value
.as_str()
.ok_or_else(|| anyhow::anyhow!("{field_name} 的模型 {key} 值必须是字符串"))?;
Ok((key.clone(), value.to_string()))
})
.collect()
}
fn validate_model_windows(model_windows: &HashMap<String, String>) -> anyhow::Result<()> {
for (slug, value) in model_windows {
if crate::model_suffix::parse_window_token(value).is_none() {
anyhow::bail!("model_windows 的模型 {slug} 窗口值无效:{value}");View on GitHub (pinned to b1ed92e5e4)