BigPizzaV3/CodexPlusPlus · error

Base URL 不能为空

Error message

Base URL 不能为空

What it means

test_relay_profile 是「测试供应商连通性」的 async 入口:向 {base_url}/responses 或 /chat/completions 发一次最小请求。发送前先取 relay_profile_base_url(profile) 并 trim、去掉尾部斜杠,若结果为空则 bail,不会发起任何网络请求。

Source

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

    }))?;
    let backup_path =
        write_codex_live_atomic(home, Some(&updated), Some(auth_contents.as_bytes()), false)?;
    let status = relay_config_status_from_home(home);
    Ok(RelayApplyResult {
        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() {
        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);

View on GitHub (pinned to 1f431ae49b)

Solutions

  1. 先保存 profile 的 base_url 再点测试
  2. 调用前检查 relay_profile_base_url(profile).trim().trim_end_matches('/') 非空
  3. 对 Aggregate 类型 profile 不要直接调用本函数测试

Example fix

// before
let r = test_relay_profile(&empty_profile, "gpt-5").await?;

// after
let base = relay_profile_base_url(&profile).trim().trim_end_matches('/').to_string();
if base.is_empty() {
    return Err(anyhow::anyhow!("Base URL 不能为空"));
}
let r = test_relay_profile(&profile, "gpt-5").await?;
Defensive patterns

Strategy: validation

Validate before calling

let base = relay_profile_base_url(profile).trim().trim_end_matches('/').to_string();
if base.is_empty() {
    return Err(anyhow::anyhow!("Base URL 不能为空"));
}
test_relay_profile(profile, model).await?;

Try / catch

if let Err(err) = test_relay_profile(&profile, &model).await {
    if err.to_string().contains("Base URL 不能为空") {
        // 提示先保存 base_url;不发网络重试
    } else { return Err(err); }
}

Prevention

When it happens

Trigger: 调用 test_relay_profile(profile, model) 时 profile 的 base_url 解析结果为空,或仅由斜杠/空白组成(如 "//" 或 "/"——trim_end_matches('/') 会把斜杠剥光变成空串)。

Common situations: 在 UI 上没保存 base_url 就点「测试」;base_url 只填了域名后缀斜杠;Aggregate 模式 profile 没有独立 base_url。

Related errors


AI-assisted analysis of BigPizzaV3/CodexPlusPlus@1f431ae49b (2026-08-16). Data as JSON: /api/errors/798a61e5763105be. Report an issue: GitHub.