{"record":{"id":"114f617df007c98b","repo":"BigPizzaV3/CodexPlusPlus","slug":"grok-alias-api","errorCode":null,"errorMessage":"Grok 模型 {alias} 的 API 协议无效","messagePattern":"Grok 模型 (.+?) 的 API 协议无效","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/grok_config.rs","lineNumber":293,"sourceCode":"        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\");\n        }\n    }\n    Ok(())\n}\n\nfn table_string(doc: &DocumentMut, table: &str, key: &str) -> String {","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/grok_config.rs#L275-L311","documentation":"validate_request only accepts three API protocol values for Grok models: \"responses\", \"chat_completions\", or \"messages\" (after trimming). Any other string — typos, camelCase variants, empty values — is rejected because the generated config would reference an unsupported backend protocol.","triggerScenarios":"save_grok_config_at called with input.api_backend set to anything other than the three exact snake_case literals, e.g. \"chatCompletions\", \"chat-completions\", \"responses_api\", or \"\".","commonSituations":"Typing the protocol by hand in a config UI; porting settings from another tool that uses different casing/hyphenation; old saved configs using a protocol name that was renamed to snake_case.","solutions":["Set api_backend to exactly \"responses\", \"chat_completions\", or \"messages\"","Trim surrounding whitespace and convert to the snake_case literal","Check existing valid config entries and copy one of the accepted values"],"exampleFix":"// before\napi_backend: \"chat-completions\"\n// after\napi_backend: \"chat_completions\"","handlingStrategy":"validation","validationCode":"const BACKENDS: [&str;3] = [\"responses\",\"chat_completions\",\"messages\"]; assert!(BACKENDS.contains(&req.api_backend.trim()));","typeGuard":"fn is_valid_backend(s: &str) -> bool { matches!(s.trim(), \"responses\" | \"chat_completions\" | \"messages\") }","tryCatchPattern":null,"preventionTips":["Use a dropdown/enum in the UI instead of free text","Normalize user input to snake_case before saving","Keep the accepted literals in one shared constant"],"tags":["validation","enum","config"],"backgroundTag":"invalid-enum-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"}