{"record":{"id":"0e8effa11750f281","repo":"BigPizzaV3/CodexPlusPlus","slug":"field-name-json-error","errorCode":null,"errorMessage":"{field_name} JSON 解析失败：{error}","messagePattern":"(.+?) JSON 解析失败：(.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/relay_config.rs","lineNumber":2103,"sourceCode":"        custom_responses.then_some(false),\n        official_deepseek_responses,\n    );\n    let catalog_json = apply_model_metadata_overrides(&catalog_json, &model_metadata)?;\n    crate::settings::atomic_write(&catalog_path, catalog_json.as_bytes())?;\n    let mut doc = parse_toml_document(&config_text)?;\n    doc[\"model_catalog_json\"] = toml_edit::value(catalog_relative);\n    Ok(normalize_optional_toml(doc))\n}\n\nfn parse_model_string_map(\n    value: &str,\n    field_name: &str,\n) -> anyhow::Result<HashMap<String, String>> {\n    if value.trim().is_empty() {\n        return Ok(HashMap::new());\n    }\n    let parsed: Value = serde_json::from_str(value)\n        .map_err(|error| anyhow::anyhow!(\"{field_name} JSON 解析失败：{error}\"))?;\n    let object = parsed\n        .as_object()\n        .ok_or_else(|| anyhow::anyhow!(\"{field_name} 必须是 JSON 对象\"))?;\n    object\n        .iter()\n        .map(|(key, value)| {\n            let value = value\n                .as_str()\n                .ok_or_else(|| anyhow::anyhow!(\"{field_name} 的模型 {key} 值必须是字符串\"))?;\n            Ok((key.clone(), value.to_string()))\n        })\n        .collect()\n}\n\nfn validate_model_windows(model_windows: &HashMap<String, String>) -> anyhow::Result<()> {\n    for (slug, value) in model_windows {\n        if crate::model_suffix::parse_window_token(value).is_none() {\n            anyhow::bail!(\"model_windows 的模型 {slug} 窗口值无效：{value}\");","sourceCodeStart":2085,"sourceCodeEnd":2121,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/relay_config.rs#L2085-L2121","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nmodel_windows = \"deepseek-v4-pro: 1000000\"\n// after\nmodel_windows = \"{\\\"deepseek-v4-pro\\\": \\\"1000000\\\"}\"","handlingStrategy":"validation","validationCode":"fn is_valid_string_map(json: &str) -> bool {\n    if json.trim().is_empty() { return true; }\n    serde_json::from_str::<serde_json::Map<String, serde_json::Value>>(json)\n        .ok()\n        .map(|m| m.values().all(|v| v.is_string()))\n        .unwrap_or(false)\n}","typeGuard":"fn as_string_map(v: &serde_json::Value) -> Option<HashMap<String, String>> {\n    v.as_object().map(|o| o.iter()\n        .filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), s.to_string())))\n        .collect())\n}","tryCatchPattern":"match normalize_relay_profile_for_storage(profile) {\n    Err(e) if e.to_string().contains(\"JSON 解析失败\") => {\n        // highlight the offending field in the UI and refuse to save\n    }\n    other => other?,\n}","preventionTips":["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"],"tags":["json","parse-error","config"],"backgroundTag":"json-parse-error","analyzedSha":"b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6","analyzedAt":"2026-09-19T23:35:21.129Z","contentChangedAt":"2026-09-19T23:35:21.129Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}