BigPizzaV3/CodexPlusPlus · error
未找到可用的聚合供应商成员
Error message
未找到可用的聚合供应商成员
What it means
Thrown at the end of the failover loop in open_responses_proxy_request_with_settings_and_user_agent (crates/codex-plus-core/src/protocol_proxy.rs:713). The loop iterates the candidate relay list (primary selection plus fallback_relays_after members, or the single model-route target); on the last candidate it always returns, so this bail is reached only when the candidate list is empty — i.e. the aggregate rotation produced no usable member to try. In effect: the active aggregate provider has no members to dispatch the request to.
Source
Thrown at crates/codex-plus-core/src/protocol_proxy.rs:713
response: upstream,
});
}
let _ = crate::diagnostic_log::append_diagnostic_log(
"protocol_proxy.upstream_failover",
json!({
"relayId": relay.id,
"relayName": relay.name,
"endpoint": endpoint,
"wireApi": wire_api,
"stream": is_stream,
"statusCode": status_code,
"attempt": attempt + 1,
"candidateCount": relay_count,
"headerTimeoutSeconds": header_timeout.as_secs()
}),
);
}
anyhow::bail!("未找到可用的聚合供应商成员")
}
fn select_model_route(
settings: &crate::settings::BackendSettings,
model: &str,
) -> anyhow::Result<Option<ModelRouteSelection>> {
if model.is_empty() || settings.active_aggregate_relay_profile().is_some() {
return Ok(None);
}
let source = settings.active_relay_profile();
let Some(route) = source
.model_routes
.iter()
.find(|route| route.model.trim() == model)
else {
return Ok(None);
};View on GitHub (pinned to 1f431ae49b)
Solutions
- Open the aggregate relay profile and add at least one member provider, then save
- Verify every member's relay_id in the aggregate still matches an existing relay profile id (deleted members leave dangling ids)
- Ensure each member relay has non-empty base_url and api_key so member validation passes
- Alternatively switch the active relay away from the empty aggregate to a concrete provider profile
Defensive patterns
Strategy: validation
Validate before calling
fn aggregate_has_usable_members(settings: &BackendSettings) -> bool {
settings
.active_aggregate_relay_profile()
.map(|agg| agg.members.iter().any(|m| {
settings.relay_profiles.iter().any(|p| {
p.id == m.relay_id
&& !p.base_url.trim().is_empty()
&& !p.api_key.trim().is_empty()
})
}))
.unwrap_or(true)
} Try / catch
let result = open_responses_proxy_request(body, path).await;
if let Err(e) = &result {
if e.to_string().contains("聚合供应商成员") {
// prompt user to configure aggregate members before retrying
}
} Prevention
- Block saving an aggregate profile with zero members in the manager UI
- When deleting a relay profile, also remove it from every aggregate's member list
- Health-check aggregate members (base_url + api_key non-empty) before activating the aggregate
When it happens
Trigger: Active relay is an aggregate whose members list is empty at request time; aggregate members were all deleted or their relay ids no longer resolve so the candidate list collapses to zero; racing settings edits removed members between selection and iteration.
Common situations: User creates an aggregate provider but never adds member relays; members deleted individually while the aggregate stayed active; settings file hand-edited to drop member entries; UI allowed saving an aggregate with zero members.
Related errors
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@1f431ae49b (2026-08-16).
Data as JSON: /api/errors/684d1ba1a374d771.
Report an issue: GitHub.