{"record":{"id":"9eb41326fbd2c569","repo":"Hmbown/CodeWhale","slug":"model-uses-but-this-client-is-bound","errorCode":null,"errorMessage":"{} model {:?} uses {:?}, but this client is bound to {:?} and no configuration is available to rebuild it","messagePattern":"(.+?) model (.+?) uses (.+?), but this client is bound to (.+?) and no configuration is available to rebuild it","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/client.rs","lineNumber":1290,"sourceCode":"        if !model_aware {\n            return Ok(None);\n        }\n        static RESOLVER: OnceLock<RouteResolver> = OnceLock::new();\n        let candidate = RESOLVER\n            .get_or_init(RouteResolver::new)\n            .resolve(&RouteRequest {\n                explicit_provider: self.api_provider.kind(),\n                model_selector: Some(LogicalModelRef::from(model)),\n                saved_provider_model: None,\n                base_url_override: Some(self.base_url.clone()),\n                limit_overrides: Vec::new(),\n            })\n            .map_err(anyhow::Error::msg)?;\n        if candidate.protocol() == self.wire_format {\n            return Ok(None);\n        }\n        let config = config.ok_or_else(|| {\n            anyhow::anyhow!(\n                \"{} model {:?} uses {:?}, but this client is bound to {:?} and no configuration is available to rebuild it\",\n                self.api_provider.display_name(),\n                model,\n                candidate.protocol(),\n                self.wire_format\n            )\n        })?;\n        Self::from_candidate(config, &candidate).map(Some)\n    }\n\n    fn bind_request_to_protocol(&self, mut request: MessageRequest) -> Result<MessageRequest> {\n        let model_aware = self.api_provider.metadata().is_some_and(|provider| {\n            provider.wire_policy() == codewhale_config::provider::WirePolicy::ModelAware\n        });\n        if !model_aware {\n            return Ok(request);\n        }\n","sourceCodeStart":1272,"sourceCodeEnd":1308,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/client.rs#L1272-L1308","documentation":"`rebound_for_model_protocol` handles providers whose wire policy is `ModelAware` — different models on the same provider can speak different wire protocols (OpenAI Responses vs Anthropic Messages vs ChatCompletions). When the central route resolver maps the requested model to a protocol different from the client's construction-time `wire_format`, the client must be rebuilt via `Self::from_candidate(config, ...)`. This error fires when a rebind is required but the caller passed `config: None`, so there is nothing to rebuild from. In practice this is hit from the subagent runtime (`tools/subagent/mod.rs`), which passes `child_runtime.api_config`.","triggerScenarios":"Launching a subagent (or any code path calling `rebound_for_model_protocol(None, model)`) whose effective model resolves to a different wire protocol than the parent client's binding — e.g. a ModelAware provider where model A is chat-completions and model B is responses — while the child runtime was created without an `api_config`.","commonSituations":"Custom ModelAware provider definitions where a subagent's model selector crosses protocol families; a programmatic embedding that constructs a client and calls subagent tooling without threading the loaded `Config` through; version drift where an older caller site was not yet updated to pass the config.","solutions":["Ensure the runtime executing the model carries the loaded configuration (pass the `Config` through so `rebound_for_model_protocol` receives `Some(config)`).","As a workaround, pin the subagent/child model to one whose resolved protocol matches the client's existing wire binding, so no rebind is needed.","If you control the provider definition, avoid mixing wire protocols under one ModelAware provider, or verify the model-to-protocol mapping in the route resolver configuration."],"exampleFix":"// before\nlet client = client.rebound_for_model_protocol(None, &model)?;\n// after\nlet client = client.rebound_for_model_protocol(Some(&config), &model)?;","handlingStrategy":"fallback","validationCode":"// Before selecting a cross-protocol model for a child runtime, ensure a Config is available.\nif client_needs_rebind(provider, model)? && child_runtime.api_config.is_none() {\n    // fall back to the parent's current model instead of failing the send\n    effective_model = parent_model.clone();\n}","typeGuard":"fn is_model_aware(provider: ApiProvider) -> bool {\n    provider.metadata().is_some_and(|m| m.wire_policy() == WirePolicy::ModelAware)\n}","tryCatchPattern":"match client.rebound_for_model_protocol(config.as_ref(), &model) {\n    Ok(Some(rebound)) => use(rebound),\n    Ok(None) => use(client),          // already correct binding\n    Err(e) if e.to_string().contains(\"no configuration is available\") => {\n        // degrade gracefully: keep the existing binding / parent model\n        fall_back_to_parent_binding();\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always thread the loaded `Config` into child runtimes (`child_runtime.api_config = Some(config)`).","When offering model pickers for ModelAware providers, annotate which models switch wire protocols.","Smoke-test subagent launches after adding new models to a ModelAware provider definition."],"tags":["routing","provider","subagent","configuration","wire-protocol"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}