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

  1. Fix the JSON in the named field: it must be an object like {"model-slug": "1000000"} with double quotes and no trailing commas.
  2. Validate the field text with a JSON parser (JSON.parse / serde_json) before saving the profile.
  3. If unsure, clear the field (leave empty) — empty string is accepted and means 'no entries'.
  4. 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

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)