{"record":{"id":"274f7a5639eea674","repo":"BigPizzaV3/CodexPlusPlus","slug":"grok-274f7a","errorCode":null,"errorMessage":"Grok 模型别名不能包含控制字符","messagePattern":"Grok 模型别名不能包含控制字符","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/grok_config.rs","lineNumber":280,"sourceCode":"        }\n        if models.contains_key(alias) {\n            bail!(\"Grok 模型别名与未管理配置冲突：{alias}\");\n        }\n        models.insert(alias, item);\n    }\n    Ok(())\n}\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","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/grok_config.rs#L262-L298","documentation":"validate_request in grok_config.rs checks each model entry of a Grok config save request. An alias containing a Unicode control character (e.g. \\n, \\t, \\r, or other C0/C1 chars) is rejected because aliases become TOML keys / identifiers and control characters would corrupt the config file and lookups. The error is raised before any file is written, so nothing is persisted.","triggerScenarios":"Calling save_grok_config_at (via validate_request) with a request.models entry whose trimmed alias contains any char for which char::is_control is true — most often from copy-pasting a name with a trailing newline/tab, or programmatic input built with line breaks.","commonSituations":"Pasting model aliases from chat or docs with trailing whitespace/newlines; generating config JSON from a script that forgot to trim; CSV/TSV parsing leaving embedded tabs in the alias field.","solutions":["Trim the alias and remove all control characters before submitting the request","Ensure each alias is a single-line printable identifier","Add input sanitization at the UI/CLI layer that strips control chars automatically"],"exampleFix":"// before\nlet alias = format!(\"grok-4\\n\");\n// after\nlet alias: String = raw_alias.trim().chars().filter(|c| !c.is_control()).collect();","handlingStrategy":"validation","validationCode":"fn valid_alias(s: &str) -> bool { let t = s.trim(); !t.is_empty() && !t.chars().any(char::is_control) }","typeGuard":"fn has_control(s: &str) -> bool { s.chars().any(char::is_control) }","tryCatchPattern":null,"preventionTips":["Always trim and strip control characters from user-supplied aliases before submit","Restrict alias inputs to a safe charset pattern (e.g. ^[A-Za-z0-9_-]+$)","Show inline validation in the UI as the user types"],"tags":["validation","config","input-sanitization"],"backgroundTag":"invalid-argument-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"}