{"record":{"id":"e4dc0a8db13ccbc1","repo":"BigPizzaV3/CodexPlusPlus","slug":"model","errorCode":null,"errorMessage":"模型路由不能指向当前供应商自身：{model}","messagePattern":"模型路由不能指向当前供应商自身：(.+?)","errorType":"http","errorClass":null,"httpStatus":502,"severity":"error","filePath":"crates/codex-plus-core/src/protocol_proxy.rs","lineNumber":734,"sourceCode":"fn select_model_route(\n    settings: &crate::settings::BackendSettings,\n    model: &str,\n) -> anyhow::Result<Option<ModelRouteSelection>> {\n    if model.is_empty() || settings.active_aggregate_relay_profile().is_some() {\n        return Ok(None);\n    }\n\n    let source = settings.active_relay_profile();\n    let Some(route) = source\n        .model_routes\n        .iter()\n        .find(|route| route.model.trim() == model)\n    else {\n        return Ok(None);\n    };\n    let target_relay_id = route.target_relay_id.trim();\n    if target_relay_id == source.id {\n        anyhow::bail!(\"模型路由不能指向当前供应商自身：{model}\");\n    }\n    let target = settings\n        .relay_profiles\n        .iter()\n        .find(|profile| profile.id == target_relay_id)\n        .cloned()\n        .with_context(|| format!(\"模型路由目标供应商不存在：{target_relay_id}\"))?;\n    if target.relay_mode == crate::settings::RelayMode::Aggregate {\n        anyhow::bail!(\"模型路由目标不能是聚合供应商：{}\", target.name);\n    }\n    if target.protocol != RelayProtocol::Responses {\n        anyhow::bail!(\"模型路由目标必须使用 Responses API：{}\", target.name);\n    }\n\n    let upstream_model = if route.target_model.trim().is_empty() {\n        model.to_string()\n    } else {\n        route.target_model.trim().to_string()","sourceCodeStart":716,"sourceCodeEnd":752,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/1f431ae49b57b3055e0e6845ba6156c6b4232b4d/crates/codex-plus-core/src/protocol_proxy.rs#L716-L752","documentation":"Thrown by select_model_route in crates/codex-plus-core/src/protocol_proxy.rs when a per-model route entry in the active relay's model_routes has target_relay_id equal to the active relay's own id. Routing a model to the source provider itself would recurse (the request would be selected and routed again), so the proxy rejects it upfront. The {model} placeholder names the model whose route triggered the error.","triggerScenarios":"Calling the Responses proxy with a model that has a model_routes entry whose target_relay_id is the source profile's id; copying a relay profile that kept its own id in model_routes after the copy became the new active profile.","commonSituations":"User duplicates a provider profile and the duplicated routes still point at the original id which is now itself; hand-editing settings.json relay ids without updating model_routes; UI allowing a self-referencing route to be saved.","solutions":["Open the active provider's model routes and change the target of the failing model to a different relay profile id","If the intent was 'do not route this model', delete the route entry entirely instead of pointing it at itself","After duplicating profiles, audit model_routes and rewrite target ids to the intended distinct profiles","Add a save-time validation in the UI/manager that rejects route.target_relay_id == profile.id"],"exampleFix":"// settings.json (before): route targets the profile itself\n\"model_routes\": [{ \"model\": \"gpt-5\", \"target_relay_id\": \"relay-a\" }]\n// while active relay id is \"relay-a\"\n\n// after: target a different profile\n\"model_routes\": [{ \"model\": \"gpt-5\", \"target_relay_id\": \"relay-b\" }]","handlingStrategy":"validation","validationCode":"fn route_targets_are_valid(profile: &RelayProfile) -> Result<(), String> {\n    for route in &profile.model_routes {\n        if route.target_relay_id.trim() == profile.id {\n            return Err(format!(\"route for {} targets the profile itself\", route.model));\n        }\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = open_responses_proxy_request(body, path).await {\n    if e.to_string().contains(\"不能指向当前供应商自身\") {\n        // open the model-routes editor for the active profile\n    }\n}","preventionTips":["Validate route.target_relay_id != profile.id at save time in the manager","When duplicating profiles, rewrite route target ids explicitly","Prefer picking targets from a dropdown of other profiles instead of typing ids"],"tags":["model-routing","configuration","self-reference","relay-profile"],"backgroundTag":"invalid-routing-config","analyzedSha":"1f431ae49b57b3055e0e6845ba6156c6b4232b4d","analyzedAt":"2026-08-16T20:54:18.598Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}