{"record":{"id":"42449e084ddae4e9","repo":"BigPizzaV3/CodexPlusPlus","slug":"id","errorCode":null,"errorMessage":"上下文 id 不能为空","messagePattern":"上下文 id 不能为空","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/relay_config.rs","lineNumber":874,"sourceCode":") -> anyhow::Result<CodexContextEntries> {\n    let normalized = normalize_duplicate_toml_text(common_config);\n    let doc = parse_toml_document(&normalized)?;\n    Ok(CodexContextEntries {\n        mcp_servers: list_context_entries_for_table(&doc, \"mcp_servers\"),\n        skills: list_context_entries_for_table(&doc, \"skills\"),\n        plugins: list_context_entries_for_table(&doc, \"plugins\"),\n    })\n}\n\npub fn upsert_context_entry_in_common_config(\n    common_config: &str,\n    kind: &str,\n    id: &str,\n    toml_body: &str,\n) -> anyhow::Result<String> {\n    let id = id.trim();\n    if id.is_empty() {\n        anyhow::bail!(\"上下文 id 不能为空\");\n    }\n    let table_name = context_table_name(kind)?;\n    let body_doc = parse_toml_document(toml_body)?;\n    let normalized = normalize_duplicate_toml_text(common_config);\n    let mut doc = parse_toml_document(&normalized)?;\n    if !doc.as_table().contains_key(table_name) {\n        doc[table_name] = toml_edit::table();\n    }\n    if doc[table_name].as_table().is_none() {\n        anyhow::bail!(\"{table_name} 必须是 TOML 表\");\n    }\n    doc[table_name][id] = Item::Table(body_doc.as_table().clone());\n    Ok(normalize_optional_toml(doc))\n}\n\npub fn delete_context_entry_from_common_config(\n    common_config: &str,\n    kind: &str,","sourceCodeStart":856,"sourceCodeEnd":892,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/1f431ae49b57b3055e0e6845ba6156c6b4232b4d/crates/codex-plus-core/src/relay_config.rs#L856-L892","documentation":"upsert_context_entry_in_common_config 用于向公共配置（common config）的 mcp_servers/skills/plugins 表里插入或更新一个条目（按 id 为键）。函数首先对 id trim 非空校验，为空立即 bail——因为空 id 无法成为 TOML 键。","triggerScenarios":"调用 upsert_context_entry_in_common_config(common_config, kind, id, toml_body) 时 id.trim() 为空。kind 非法走的是另一个错误（[72] 未知上下文类型），且本校验先于 kind 校验执行。","commonSituations":"MCP/Skill/Plugin 编辑器里 id/名称输入框为空就点保存；从导入数据里取 id 字段时缺失；用空格命名条目。","solutions":["为条目填写非空 id（如 MCP server 名）再调用","调用前对 id.trim() 做表单校验","导入流程中对缺失 id 的条目跳过或生成默认 id"],"exampleFix":"// before\nlet cfg = upsert_context_entry_in_common_config(&common, \"mcp\", \"\", &body)?;\n\n// after\nlet id = id.trim();\nanyhow::ensure!(!id.is_empty(), \"上下文 id 不能为空\");\nlet cfg = upsert_context_entry_in_common_config(&common, \"mcp\", id, &body)?;","handlingStrategy":"validation","validationCode":"let id = id.trim();\nanyhow::ensure!(!id.is_empty(), \"上下文 id 不能为空\");\nupsert_context_entry_in_common_config(&common, kind, id, toml_body)?;","typeGuard":null,"tryCatchPattern":"match upsert_context_entry_in_common_config(&common, kind, id, body) {\n    Ok(new_common) => common = new_common,\n    Err(err) if err.to_string().contains(\"上下文 id 不能为空\") => { /* 表单提示 */ }\n    Err(err) => return Err(err),\n}","preventionTips":["条目编辑器对 id/名称做必填校验","导入数据时对缺失 id 的条目跳过并记录","id trim 后再使用，避免纯空白混入"],"tags":["common-config","mcp","context-entry","validation"],"backgroundTag":"empty-required-field","analyzedSha":"1f431ae49b57b3055e0e6845ba6156c6b4232b4d","analyzedAt":"2026-08-16T20:54:18.598Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}