{"record":{"id":"c6a2d05f063a1385","repo":"BigPizzaV3/CodexPlusPlus","slug":"grok-source","errorCode":null,"errorMessage":"Grok 模型来源别名重复：{source}","messagePattern":"Grok 模型来源别名重复：(.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/grok_config.rs","lineNumber":287,"sourceCode":"}\n\nfn validate_request(request: &SaveGrokConfigRequest) -> anyhow::Result<()> {\n    let mut aliases = HashSet::new();\n    let mut sources = HashSet::new();\n    for input in &request.models {\n        let alias = input.alias.trim();\n        if alias.is_empty() {\n            bail!(\"Grok 模型别名不能为空\");\n        }\n        if alias.chars().any(char::is_control) {\n            bail!(\"Grok 模型别名不能包含控制字符\");\n        }\n        if !aliases.insert(alias.to_string()) {\n            bail!(\"Grok 模型别名重复：{alias}\");\n        }\n        let source = input.source_alias.trim();\n        if !source.is_empty() && !sources.insert(source.to_string()) {\n            bail!(\"Grok 模型来源别名重复：{source}\");\n        }\n        if !matches!(\n            input.api_backend.trim(),\n            \"responses\" | \"chat_completions\" | \"messages\"\n        ) {\n            bail!(\"Grok 模型 {alias} 的 API 协议无效\");\n        }\n        if input.context_window == Some(0) {\n            bail!(\"Grok 模型 {alias} 的上下文窗口必须大于 0\");\n        }\n        if input\n            .context_window\n            .is_some_and(|value| value > i64::MAX as u64)\n        {\n            bail!(\"Grok 模型 {alias} 的上下文窗口过大\");\n        }\n        if input.remove_api_key && !input.api_key_update.is_empty() {\n            bail!(\"Grok 模型 {alias} 不能同时替换并移除 API Key\");","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/grok_config.rs#L269-L305","documentation":"Each model entry may declare a source_alias (upstream model it maps from). validate_request requires non-empty source aliases to be unique across the request. A duplicate causes this error and aborts the save, preventing two local aliases from ambiguously resolving to conflicting upstream definitions.","triggerScenarios":"save_grok_config_at called with two entries whose trimmed source_alias is identical and non-empty (sources.insert returns false).","commonSituations":"Mapping several local names to the same upstream alias via a copy-paste template; bulk import scripts generating the same source_alias for multiple models when only one mapping was intended.","solutions":["Give each entry a distinct source_alias","If two local aliases should share one upstream source, verify the tooling supports that or split into separate saves","Trim/normalize source_alias strings before comparing"],"exampleFix":"// before\n[{alias:\"a\", source_alias:\"grok-4\"}, {alias:\"b\", source_alias:\"grok-4\"}]\n// after\n[{alias:\"a\", source_alias:\"grok-4\"}, {alias:\"b\", source_alias:\"grok-4-preview\"}]","handlingStrategy":"validation","validationCode":"let srcs: HashSet<&str> = request.models.iter().filter_map(|m| { let s = m.source_alias.trim(); if s.is_empty() { None } else { Some(s) } }).collect(); assert_eq!(srcs.len(), count_nonempty);","typeGuard":null,"tryCatchPattern":"if let Err(e) = save_grok_config_at(...) { if e.to_string().contains(\"来源别名重复\") { /* dedupe source aliases */ } }","preventionTips":["Generate source aliases from a template that guarantees uniqueness","Normalize (trim/case-fold) source aliases before comparison","Validate the whole model list client-side before save"],"tags":["validation","duplicate","config"],"backgroundTag":"schema-validation-failed","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"}