zeroclaw-labs/zeroclaw · error
ModelPinnedProviderBuilder: inner() is required
Error message
ModelPinnedProviderBuilder: inner() is required
What it means
ModelPinnedProviderBuilder.build() requires the delegate provider via .inner(); the pinned wrapper has nothing to route to without it. This expect() panic fires when .inner() was never called. Together with pinned_model() (error 1522) it forms the builder's mandatory contract.
Source
Thrown at crates/zeroclaw-providers/src/model_pin.rs:54
/// The inner provider whose model this pin overrides. Required.
pub fn inner(mut self, inner: Box<dyn ModelProvider>) -> Self {
self.inner = Some(inner);
self
}
/// # Panics
/// Panics if [`Self::pinned_model`] or [`Self::inner`] was not
/// called — neither has a sensible default.
pub fn build(self) -> ModelPinnedProvider {
ModelPinnedProvider {
alias: self.alias,
pinned_model: self
.pinned_model
.expect("ModelPinnedProviderBuilder: pinned_model() is required"),
inner: self
.inner
.expect("ModelPinnedProviderBuilder: inner() is required"),
}
}
}
impl ModelPinnedProvider {
/// Entry point. Only `alias` is taken positionally; the required
/// `pinned_model` and `inner` provider both go through labelled
/// chain methods so call sites cannot silently swap them.
pub fn builder(alias: &str) -> ModelPinnedProviderBuilder {
ModelPinnedProviderBuilder {
alias: alias.to_string(),
pinned_model: None,
inner: None,
}
}
pub(crate) fn pinned_model(&self) -> &str {
&self.pinned_modelView on GitHub (pinned to 88bb9c8533)
Solutions
- Call .inner(Box::new(provider)) (any ModelProvider implementation) before .build().
- Build the inner provider first, then the pinned wrapper, so inner is always available at construction time.
- Cover new pinning setups with a construction test to catch the missing setter in CI.
Example fix
// before
let p = ModelPinnedProvider::builder()
.alias("fast")
.pinned_model("gpt-4o-mini")
.build(); // panics: inner() is required
// after
let p = ModelPinnedProvider::builder()
.alias("fast")
.pinned_model("gpt-4o-mini")
.inner(Box::new(inner_provider))
.build(); Defensive patterns
Strategy: validation
Validate before calling
// Build the delegate first so inner is provably available:
let inner: Box<dyn ModelProvider> = make_inner_provider(&config)?; // Result-returning
let provider = ModelPinnedProvider::builder()
.alias(alias)
.pinned_model(model)
.inner(inner)
.build(); Try / catch
let provider = std::panic::catch_unwind(|| builder.build())
.map_err(|_| anyhow::anyhow!("ModelPinnedProviderBuilder contract violated: inner provider required"))?; Prevention
- Construct the inner provider before the pinned wrapper so .inner() cannot be forgotten.
- Make inner-provider creation Result-returning so failures surface as errors, not skipped setters.
- Keep a construction test covering alias + pinned_model + inner in one place.
When it happens
Trigger: Constructing ModelPinnedProvider with .alias(...) and .pinned_model(...) but no .inner(provider) call before .build().
Common situations: Copy-pasting a pinned-provider setup and forgetting the delegate; refactoring provider wiring so the inner provider value is produced later than build() and the setter call is dropped.
Related errors
- ModelPinnedProviderBuilder: pinned_model() is required
- OpenAiCompatibleBuilder: base_url() is required
- OpenAiCompatibleBuilder: auth_style() is required
- purge_agent not supported by this memory backend
- rename_agent not supported by this memory backend
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/7d51e9ea23afff7c.
Report an issue: GitHub.