{"record":{"id":"6b2f1088ecac12ff","repo":"BigPizzaV3/CodexPlusPlus","slug":"api-custom-provider-config-toml","errorCode":null,"errorMessage":"纯 API 配置写入后未检测到完整 custom provider，请检查 config.toml 和供应商 API Key。","messagePattern":"纯 API 配置写入后未检测到完整 custom provider，请检查 config\\.toml 和供应商 API Key。","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/relay_switch.rs","lineNumber":156,"sourceCode":"        let auth_contents =\n            (!relay.auth_contents.trim().is_empty()).then_some(relay.auth_contents.as_str());\n        crate::relay_config::clear_relay_config_to_home_with_auth_and_computer_use_guard(\n            home,\n            auth_contents,\n            settings.computer_use_guard_enabled,\n        )?\n    } else {\n        validate_switch_profile_files(&relay)?;\n        crate::relay_config::apply_relay_profile_to_home_with_switch_rules_and_computer_use_guard(\n            home,\n            &relay,\n            &common_config,\n            settings.computer_use_guard_enabled,\n        )?\n    };\n    let status = relay_config_status_from_home(home);\n    if relay.relay_mode == RelayMode::PureApi && !status.configured {\n        anyhow::bail!(\n            \"纯 API 配置写入后未检测到完整 custom provider，请检查 config.toml 和供应商 API Key。\"\n        );\n    }\n    Ok(RelaySwitchResult {\n        settings: settings.clone(),\n        configured: status.configured,\n        backup_path: result.backup_path,\n    })\n}\n\nfn validate_switch_profile_files(profile: &crate::settings::RelayProfile) -> anyhow::Result<()> {\n    if profile.relay_mode != RelayMode::Aggregate && profile.config_contents.trim().is_empty() {\n        anyhow::bail!(\n            \"供应商「{}」缺少独立 config.toml，已停止切换，避免继续显示上一套配置文件。\",\n            if profile.name.trim().is_empty() {\n                profile.id.as_str()\n            } else {\n                profile.name.as_str()","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/1f431ae49b57b3055e0e6845ba6156c6b4232b4d/crates/codex-plus-core/src/relay_switch.rs#L138-L174","documentation":"apply_selected_relay_profile 在 PureApi 模式写入完成后，用 relay_config_status_from_home 复核：configured 要求 config.toml 有 model_provider 根键、对应 provider 有非空 base_url、且有 experimental_bearer_token 或 auth.json 里存在 API key。三项任缺即 configured=false，PureApi 模式下随即 bail 本错误。注意此时文件已写入，外层 switch 会尝试用切换前快照回滚。","triggerScenarios":"PureApi profile 的 config_contents 模板缺 base_url / model_provider 键，或 api_key 为空导致 auth.json 无 OPENAI_API_KEY 且 provider 无 bearer token，写入后复核不通过。","commonSituations":"PureApi profile 只填了 key 没生成完整 config 模板；手写 config.toml 漏掉 [model_providers.x] 的 base_url；profile 数据迁移后字段丢失。","solutions":["确认 PureApi profile 的 base_url 与 API Key 均非空","打开（备份中的）config.toml 检查 model_provider 根键与对应 [model_providers.*] 是否含 base_url","修好 profile 后重新执行切换，让写入-复核流程重跑"],"exampleFix":"# before (profile config template 缺字段)\n[model_providers.my]\nname = \"my\"\n\n# after\nmodel_provider = \"my\"\n\n[model_providers.my]\nname = \"my\"\nbase_url = \"https://api.example.com/v1\"","handlingStrategy":"validation","validationCode":"fn pure_api_profile_looks_complete(profile: &RelayProfile) -> bool {\n    !relay_profile_base_url(profile).trim().is_empty()\n        && !relay_profile_api_key(profile).trim().is_empty()\n        && profile.config_contents.contains(\"base_url\")\n        && profile.config_contents.contains(\"model_provider\")\n}\nanyhow::ensure!(pure_api_profile_looks_complete(&profile), \"纯 API 配置不完整\");\n// 之后再执行切换","typeGuard":null,"tryCatchPattern":"match switch_relay_profile_in_home(&store, &home, next, &prev) {\n    Ok(r) => Ok(r),\n    Err(err) if err.to_string().contains(\"未检测到完整 custom provider\") => {\n        // 外层已回滚实时文件；补全 profile 的 base_url / key 后再重试\n        Err(err)\n    }\n    Err(err) => Err(err),\n}","preventionTips":["PureApi profile 保存时校验 base_url、API Key 与 config 模板三要素","config 模板必须包含 model_provider 根键和 provider 的 base_url","理解 configured 判定：provider 需有 bearer token 或 auth.json 有 key"],"tags":["pure-api","post-write-validation","relay-switch","provider"],"backgroundTag":"post-write-validation-failed","analyzedSha":"1f431ae49b57b3055e0e6845ba6156c6b4232b4d","analyzedAt":"2026-08-16T20:54:18.598Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}