{"record":{"id":"de54e3e1a759b2c5","repo":"BigPizzaV3/CodexPlusPlus","slug":"model-windows-slug-value","errorCode":null,"errorMessage":"model_windows 的模型 {slug} 窗口值无效：{value}","messagePattern":"model_windows 的模型 (.+?) 窗口值无效：(.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/relay_config.rs","lineNumber":2121,"sourceCode":"        .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}\");\n        }\n    }\n    Ok(())\n}\n\nfn validate_model_auto_compact(model_auto_compact: &HashMap<String, String>) -> anyhow::Result<()> {\n    for (slug, value) in model_auto_compact {\n        if crate::model_suffix::parse_compact_percent(value).is_none() {\n            anyhow::bail!(\"model_auto_compact 的模型 {slug} 百分比无效：{value}\");\n        }\n    }\n    Ok(())\n}\n\nfn parse_model_metadata_map(metadata_json: &str) -> anyhow::Result<serde_json::Map<String, Value>> {\n    if metadata_json.trim().is_empty() {\n        return Ok(serde_json::Map::new());\n    }","sourceCodeStart":2103,"sourceCodeEnd":2139,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/relay_config.rs#L2103-L2139","documentation":"validate_model_windows checks each (slug, window) pair in the model_windows map by parsing the value with parse_window_token. If a value is not a recognized window token (e.g. \"1M\", \"256k\" format), the function bails naming the offending model slug and value, preventing an invalid suffix from being written into model_list.","triggerScenarios":"Calling the apply/validate path with model_windows containing a value like \"1,000,000\", \"100mb\", \"abc\", or a lowercase/wrong-unit token that parse_window_token rejects.","commonSituations":"User typed a raw token count or a unit the parser doesn't accept into the per-model window field; values imported from another tool use a different suffix format; locale-formatted numbers with commas.","solutions":["Use a supported window token format (e.g. \"1M\", \"256k\") matching model_suffix::parse_window_token's grammar","Normalize imported values before inserting them into model_windows","Add UI-side validation mirroring parse_window_token so bad values are caught at entry"],"exampleFix":"// before\nmodel_windows.insert(\"deepseek-v4-pro\".into(), \"1,000,000\".into());\n// after\nmodel_windows.insert(\"deepseek-v4-pro\".into(), \"1M\".into());","handlingStrategy":"validation","validationCode":"fn valid_window(v: &str) -> bool {\n    crate::model_suffix::parse_window_token(v).is_some()\n}","typeGuard":"fn is_window_token(v: &str) -> bool {\n    crate::model_suffix::parse_window_token(v).is_some()\n}","tryCatchPattern":"match apply_relay_profile(...) {\n    Err(e) if e.to_string().contains(\"窗口值无效\") => show_window_format_hint(e),\n    other => other?,\n}","preventionTips":["Validate window values with parse_window_token at input time","Use dropdown presets (128k/256k/1M) instead of free text","Normalize imported windows (raw tokens → k/M suffix) before applying"],"tags":["validation","format","config"],"backgroundTag":"invalid-config-value","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"}