zeroclaw-labs/zeroclaw · error
OpenAiCompatibleBuilder: base_url() is required
Error message
OpenAiCompatibleBuilder: base_url() is required
What it means
OpenAiCompatibleBuilder is the builder for OpenAI-compatible model providers in zeroclaw-providers. Its build() method treats display_name, base_url, and auth_style as mandatory setters and panics via expect() when any was skipped. This panic means .base_url() was never called before .build(), i.e. the builder contract was violated.
Source
Thrown at crates/zeroclaw-providers/src/compatible.rs:555
self.auth_profile_override = profile_override;
self
}
/// Finalize the builder into a ready provider. Every optional construction
/// value must be set on this builder; the returned provider has no
/// post-construction mutators.
///
/// # Panics
/// Panics if [`Self::display_name`], [`Self::base_url`], or
/// [`Self::auth_style`] was not called — those three fields carry no
/// sensible default and every real call site sets them.
pub fn build(self) -> OpenAiCompatibleModelProvider {
let name = self
.name
.expect("OpenAiCompatibleBuilder: display_name() is required");
let base_url = self
.base_url
.expect("OpenAiCompatibleBuilder: base_url() is required");
let auth_style = self
.auth_style
.expect("OpenAiCompatibleBuilder: auth_style() is required");
// Either merge preset can enable the shared merge behavior.
let merge_system_into_user =
self.merge_system_into_user || self.merge_system_into_user_preserve_native;
// Default `native_tool_calling` is `!merge_system_into_user_disable_native`,
// i.e. only the "combined preset" builder setter disables it. The
// explicit `without_native_tools()` override wins if present.
let native_tool_calling = self
.native_tool_calling_override
.unwrap_or(!self.merge_system_into_user);
// Read the PEM bytes now so later HTTP clients incur no per-request I/O.
// A read error is logged at WARN and TLS falls back to system roots —
// preserving the established warning-and-fallback semantics.
let tls_ca_cert_pem =
self.tls_ca_cert_path
.as_deref()View on GitHub (pinned to 88bb9c8533)
Solutions
- Call .base_url(url) on the builder before .build() (and verify display_name() and auth_style() are also set, they panic the same way).
- Trace the failing call through make_model_provider/http_client/streaming_http_client to find where the base URL should be injected and why it is None.
- If the URL comes from env/config, validate its presence early and return a descriptive error instead of letting build() panic.
- Add a construction unit test for every new provider preset so a missing setter fails in CI, not at runtime.
Example fix
// before
let provider = OpenAiCompatibleModelProvider::builder()
.display_name("my-llm")
.auth_style(AuthStyle::Bearer)
.build(); // panics: base_url() is required
// after
let provider = OpenAiCompatibleModelProvider::builder()
.display_name("my-llm")
.base_url("https://api.example.com/v1")
.auth_style(AuthStyle::Bearer)
.build(); Defensive patterns
Strategy: validation
Validate before calling
// Before building, resolve the endpoint URL and fail with a clear error:
let base_url = std::env::var("MY_PROVIDER_BASE_URL")
.or_else(|_| config.provider_endpoint.clone().ok_or_else(|| anyhow::anyhow!("base URL missing")))?;
let provider = OpenAiCompatibleModelProvider::builder()
.display_name("my-llm")
.base_url(base_url)
.auth_style(AuthStyle::Bearer)
.build(); Try / catch
// Embedding code that must not abort:
let provider = std::panic::catch_unwind(|| builder.build())
.map_err(|_| anyhow::anyhow!("provider builder contract violated: display_name/base_url/auth_style required"))?; Prevention
- Treat display_name, base_url, and auth_style as one mandatory bundle; set them adjacently in every construction site.
- Resolve all three from config up front and error with a field-level message instead of conditionally calling setters.
- Add a construction unit test per provider preset so missing setters fail in CI.
When it happens
Trigger: Calling OpenAiCompatibleModelProvider::builder()...build() (directly or through http_client(), streaming_http_client(), or make_model_provider()) without a prior .base_url(url) call. Typically the setter is skipped because the URL comes from config/env and an if-let around it silently falls through.
Common situations: Adding a new OpenAI-compatible provider integration and wiring api_key/model but forgetting the endpoint URL; a config field rename (e.g. endpoint vs base_url) leaving the setter unpopulated; an absent env var making a conditional setter call not execute.
Related errors
- OpenAiCompatibleBuilder: auth_style() is required
- ModelPinnedProviderBuilder: pinned_model() is required
- ModelPinnedProviderBuilder: inner() is required
- ACP returned unknown optionId: {option_id}
- {} model list failed at {url}: HTTP {status}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/e35dbcf64045fcd5.
Report an issue: GitHub.