BigPizzaV3/CodexPlusPlus · error

API Key 为空

Error message

API Key 为空

What it means

Thrown by `normalize_request` in provider_import.rs when `api_key` is empty after trimming. The key is required because it is embedded into the generated auth/config contents for the provider; an import without a key would produce a config that cannot authenticate. This is the third of three sequential required-field checks (name, base_url, api_key).

Solutions

  1. Supply the actual API key in `request.api_key` before importing.
  2. If the key comes from an env var, check it is set and non-empty (e.g. `std::env::var("MY_KEY")?`) before building the request.
  3. In UI flows, require the key field (password input) before enabling the import button.

Example fix

// before
let req = ProviderImportRequest { api_key: std::env::var("RELAY_KEY").unwrap_or_default(), .. };
// after
let req = ProviderImportRequest { api_key: std::env::var("RELAY_KEY").expect("RELAY_KEY must be set"), .. };
Defensive patterns

Strategy: validation

Validate before calling

let key = request.api_key.trim();
if key.is_empty() {
    return Err(anyhow::anyhow!("API Key 不能为空"));
}
request.api_key = key.to_string();

Type guard

fn has_api_key(req: &ProviderImportRequest) -> bool { !req.api_key.trim().is_empty() }

Try / catch

match import_provider_with_store(&store, request) {
    Ok(p) => Ok(p),
    Err(e) if e.to_string().contains("API Key 为空") => Err(anyhow::anyhow!("请填写 API Key(可从环境变量读取)")),
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Calling `import_provider_with_store` with an `api_key` of `""` or whitespace-only while name and base_url are valid; bails at provider_import.rs:231.

Common situations: User skipped the key field intending to fill it later; environment variable holding the key was unset so an empty string was interpolated; key was stripped by a sanitizer or secret-scanning step.

Understand the failure class

Background: "API key is required" / "API key not found" / "No API key was set": the missing-api-key error family across 16 libraries — this error's family across 16 libraries.

Related errors


AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19). Data as JSON: /api/errors/0798c387965f1d20. Report an issue: GitHub.

Appendix: source

Thrown at crates/codex-plus-core/src/provider_import.rs:231

        model_routes: Vec::new(),
        standard_openai_protocol: false,
    }
}

fn normalize_request(mut request: ProviderImportRequest) -> anyhow::Result<ProviderImportRequest> {
    request.name = request.name.trim().to_string();
    request.base_url = request.base_url.trim().trim_end_matches('/').to_string();
    request.api_key = request.api_key.trim().to_string();
    request.wire_api = request.wire_api.trim().to_ascii_lowercase();
    request.relay_mode = request.relay_mode.trim().to_ascii_lowercase();
    if request.name.is_empty() {
        anyhow::bail!("供应商名称为空");
    }
    if request.base_url.is_empty() {
        anyhow::bail!("Base URL 为空");
    }
    if request.api_key.is_empty() {
        anyhow::bail!("API Key 为空");
    }
    request.config_contents = build_config_toml(
        &request.base_url,
        &request.api_key,
        relay_protocol(&request.wire_api),
    );
    request.auth_contents = build_auth_json(&request.api_key);
    Ok(request)
}

fn relay_protocol(value: &str) -> RelayProtocol {
    match value.trim().to_ascii_lowercase().as_str() {
        "chat" | "chat_completions" | "chat-completions" => RelayProtocol::ChatCompletions,
        _ => RelayProtocol::Responses,
    }
}

fn relay_mode(value: &str) -> RelayMode {

View on GitHub (pinned to b1ed92e5e4)