BigPizzaV3/CodexPlusPlus · error
上游 Key 不能为空
Error message
上游 Key 不能为空
What it means
Thrown by validate_upstream in crates/codex-plus-core/src/protocol_proxy.rs when a relay candidate picked to serve a proxied request has an empty api_key. Requests are authenticated with bearer_auth(relay.api_key); the proxy fails fast on blank keys instead of sending an unauthenticated request that would surface as an upstream 401.
Source
Thrown at crates/codex-plus-core/src/protocol_proxy.rs:1011
) -> reqwest::RequestBuilder {
let mut builder = client
.post(endpoint)
.bearer_auth(api_key)
.header(reqwest::header::CONTENT_TYPE, "application/json");
if is_stream {
builder = builder
.header(reqwest::header::ACCEPT, "text/event-stream")
.header(reqwest::header::CACHE_CONTROL, "no-cache");
}
builder.json(upstream_body)
}
fn validate_upstream(relay: &crate::settings::RelayProfile) -> anyhow::Result<()> {
if relay.base_url.trim().is_empty() {
anyhow::bail!("上游 Base URL 不能为空");
}
if relay.api_key.trim().is_empty() {
anyhow::bail!("上游 Key 不能为空");
}
Ok(())
}
fn conversation_id_from_responses_request(body: &Value) -> Option<String> {
for key in ["conversation", "conversation_id", "previous_response_id"] {
if let Some(value) = body.get(key).and_then(Value::as_str) {
let value = value.trim();
if !value.is_empty() {
return Some(value.to_string());
}
}
}
None
}
fn effective_user_agent(configured_user_agent: &str, original_user_agent: Option<&str>) -> String {
let configured_user_agent = configured_user_agent.trim();View on GitHub (pinned to 1f431ae49b)
Solutions
- Find the failing relay via the diagnostic log (protocol_proxy.upstream_request includes relayName) and set its API key
- Remove or disable keyless member profiles from the aggregate so rotation skips them
- When importing providers, always include the apiKey so the created profile is complete
Defensive patterns
Strategy: validation
Validate before calling
fn all_candidates_have_api_key(settings: &BackendSettings) -> bool {
settings
.relay_profiles
.iter()
.filter(|p| settings
.active_aggregate_relay_profile()
.map(|a| a.members.iter().any(|m| m.relay_id == p.id))
.unwrap_or(p.id == settings.active_relay_id))
.all(|p| !p.api_key.trim().is_empty())
} Prevention
- Require api_key on every relay profile at save time
- Remove keyless placeholder profiles from aggregate pools
- Check the diagnostic log relayName field when this fires to find the blank profile
When it happens
Trigger: Rotation lands on an aggregate member whose api_key is blank; the active relay's key was cleared or never entered; a model-route target profile has no key.
Common situations: Member profiles added to an aggregate as placeholders; key rotation left a profile temporarily keyless while it stayed in the pool; imported profiles whose apiKey parameter was omitted.
Related errors
- Chat Completions 上游 Key 不能为空
- 上游 Base URL 不能为空
- 未找到可用的聚合供应商成员
- Chat Completions 上游 Base URL 不能为空
- API Key 为空
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@1f431ae49b (2026-08-16).
Data as JSON: /api/errors/4943931c336951ca.
Report an issue: GitHub.