BigPizzaV3/CodexPlusPlus · error

API Key 不能为空

Error message

API Key 不能为空

What it means

test_relay_profile requires an API key for authentication unless the profile explicitly opts into no-auth mode via uses_no_auth(). If the trimmed key is empty and the profile does not use no-auth, the library bails instead of sending an unauthenticated request that would fail server-side.

Solutions

  1. Set the API key on the RelayProfile before testing
  2. If the relay truly needs no auth, mark the profile as no-auth so uses_no_auth() returns true
  3. Pass an explicit key through the test call path if the UI collects one separately

Example fix

// before
let profile = RelayProfile { api_key: "", uses_no_auth: false, .. };
// after
let profile = RelayProfile { api_key: "sk-...", uses_no_auth: false, .. };
// or
let profile = RelayProfile { api_key: "", uses_no_auth: true, .. };
Defensive patterns

Strategy: validation

Validate before calling

if relay_profile_api_key(profile).trim().is_empty() && !profile.uses_no_auth() {
    return Err(anyhow::anyhow!("API Key 不能为空"));
}

Try / catch

match test_relay_profile(&profile, model) {
    Err(e) if e.to_string().contains("API Key 不能为空") => open_api_key_dialog(),
    other => other?,
}

Prevention

When it happens

Trigger: Calling test_relay_profile with a profile whose relay_profile_api_key(profile) is empty/whitespace and profile.uses_no_auth() is false.

Common situations: User created a profile but forgot to paste the relay key; a key was redacted or stripped when exporting/importing profile settings; user assumes the relay is anonymous but didn't enable the no-auth option.

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/4df38db34d186a9e. Report an issue: GitHub.

Appendix: source

Thrown at crates/codex-plus-core/src/relay_config.rs:672

        config_path: status.config_path,
        backup_path,
        configured: status.configured,
    })
}

pub async fn test_relay_profile(
    profile: &RelayProfile,
    model: &str,
) -> anyhow::Result<RelayProfileTestResult> {
    let base_url = relay_profile_base_url(profile);
    let base_url = base_url.trim().trim_end_matches('/');
    if base_url.is_empty() {
        anyhow::bail!("Base URL 不能为空");
    }
    let api_key = relay_profile_api_key(profile);
    let api_key = api_key.trim();
    if api_key.is_empty() && !profile.uses_no_auth() {
        anyhow::bail!("API Key 不能为空");
    }

    let client = crate::http_client::proxied_client("CodexPlusPlus/RelayTest")?;
    let endpoint = match profile.protocol {
        RelayProtocol::Responses => format!("{base_url}/responses"),
        RelayProtocol::ChatCompletions => format!("{base_url}/chat/completions"),
    };
    let test_model = model.trim();
    if test_model.is_empty() {
        anyhow::bail!("测试模型不能为空");
    }

    let payload = relay_profile_test_payload(profile.protocol, test_model);
    let mut request = client
        .post(&endpoint)
        .header(reqwest::header::CONTENT_TYPE, "application/json")
        .json(&payload);
    if !profile.uses_no_auth() {

View on GitHub (pinned to b1ed92e5e4)