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
- Provide the relay/provider endpoint, e.g. `base_url: "https://api.example.com/v1"`, in the request.
- Validate the URL is non-empty and well-formed in the UI/CLI before invoking the import.
- 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
- Use a URL input with client-side format validation in the UI.
- Trim and strip trailing slashes from user-entered URLs before submitting.
- Check templates/JSON imports actually populate base_url.
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)