{"record":{"id":"7d51e9ea23afff7c","repo":"zeroclaw-labs/zeroclaw","slug":"modelpinnedproviderbuilder-inner-is-required","errorCode":null,"errorMessage":"ModelPinnedProviderBuilder: inner() is required","messagePattern":"ModelPinnedProviderBuilder: inner\\(\\) is required","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-providers/src/model_pin.rs","lineNumber":54,"sourceCode":"\n    /// The inner provider whose model this pin overrides. Required.\n    pub fn inner(mut self, inner: Box<dyn ModelProvider>) -> Self {\n        self.inner = Some(inner);\n        self\n    }\n\n    /// # Panics\n    /// Panics if [`Self::pinned_model`] or [`Self::inner`] was not\n    /// called — neither has a sensible default.\n    pub fn build(self) -> ModelPinnedProvider {\n        ModelPinnedProvider {\n            alias: self.alias,\n            pinned_model: self\n                .pinned_model\n                .expect(\"ModelPinnedProviderBuilder: pinned_model() is required\"),\n            inner: self\n                .inner\n                .expect(\"ModelPinnedProviderBuilder: inner() is required\"),\n        }\n    }\n}\n\nimpl ModelPinnedProvider {\n    /// Entry point. Only `alias` is taken positionally; the required\n    /// `pinned_model` and `inner` provider both go through labelled\n    /// chain methods so call sites cannot silently swap them.\n    pub fn builder(alias: &str) -> ModelPinnedProviderBuilder {\n        ModelPinnedProviderBuilder {\n            alias: alias.to_string(),\n            pinned_model: None,\n            inner: None,\n        }\n    }\n\n    pub(crate) fn pinned_model(&self) -> &str {\n        &self.pinned_model","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-providers/src/model_pin.rs#L36-L72","documentation":"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.","triggerScenarios":"Constructing ModelPinnedProvider with .alias(...) and .pinned_model(...) but no .inner(provider) call before .build().","commonSituations":"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.","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."],"exampleFix":"// before\nlet p = ModelPinnedProvider::builder()\n    .alias(\"fast\")\n    .pinned_model(\"gpt-4o-mini\")\n    .build(); // panics: inner() is required\n\n// after\nlet p = ModelPinnedProvider::builder()\n    .alias(\"fast\")\n    .pinned_model(\"gpt-4o-mini\")\n    .inner(Box::new(inner_provider))\n    .build();","handlingStrategy":"validation","validationCode":"// Build the delegate first so inner is provably available:\nlet inner: Box<dyn ModelProvider> = make_inner_provider(&config)?; // Result-returning\nlet provider = ModelPinnedProvider::builder()\n    .alias(alias)\n    .pinned_model(model)\n    .inner(inner)\n    .build();","typeGuard":null,"tryCatchPattern":"let provider = std::panic::catch_unwind(|| builder.build())\n    .map_err(|_| anyhow::anyhow!(\"ModelPinnedProviderBuilder contract violated: inner provider required\"))?;","preventionTips":["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."],"tags":["rust","builder","panic","model-pinning","provider"],"backgroundTag":"builder-missing-required-field","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}