BigPizzaV3/CodexPlusPlus · error

Base URL 为空

Error message

Base URL 为空

What it means

Thrown by `normalize_request` in provider_import.rs when the provider's `base_url` is empty or whitespace-only after trimming (the code also strips trailing slashes but the emptiness check comes first). The base URL is mandatory because it is baked into the generated config.toml endpoint for the provider. Without it the generated provider config would point nowhere, so import aborts.

Solutions

  1. Provide the relay/provider endpoint, e.g. `base_url: "https://api.example.com/v1"`, in the request.
  2. Validate the URL is non-empty and well-formed in the UI/CLI before invoking the import.
  3. Check that any template or JSON source actually populates `base_url` (no placeholder left empty).

Example fix

// before
request.base_url = "".to_string();
// after
request.base_url = "https://api.example.com/v1".to_string();
Defensive patterns

Strategy: validation

Validate before calling

let base = request.base_url.trim().trim_end_matches('/');
if base.is_empty() || !base.starts_with("http") {
    return Err(anyhow::anyhow!("Base URL 不能为空且必须是合法 http(s) URL"));
}
request.base_url = base.to_string();

Type guard

fn has_base_url(req: &ProviderImportRequest) -> bool {
    req.base_url.trim().starts_with("http://") || req.base_url.trim().starts_with("https://")
}

Try / catch

match import_provider_with_store(&store, request) {
    Ok(p) => Ok(p),
    Err(e) if e.to_string().contains("Base URL 为空") => Err(anyhow::anyhow!("请在表单中填写中转站地址")),
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Calling `import_provider_with_store` with a request whose `base_url` is `""`, `" "`, or missing, after the name check passed; normalize_request bails at provider_import.rs:228.

Common situations: User pasted only an API key and forgot the endpoint; a clipboard/template import left the URL field blank; building the request programmatically with a default-constructed struct.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

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

        user_agent: String::new(),
        sub2api_enabled: false,
        sub2api_multiplier: String::new(),
        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,
    }

View on GitHub (pinned to b1ed92e5e4)