Hmbown/CodeWhale · error · anyhow::Error

model uses , but this client is bound to and no…

Error message

{provider} model {model} uses {candidate_protocol}, but this client is bound to {wire_format} and no configuration is available to rebuild it

What it means

rebound_for_model_protocol resolves the requested model through the route resolver; when the resolved protocol differs from the wire format this client was built with, the client must be rebuilt from the original Config. This error is raised when a cross-protocol model switch is requested but the `config` argument is None, so no rebuild is possible. It exists to guarantee a client never silently sends requests in the wrong wire dialect (e.g. Anthropic Messages payload to a Chat Completions endpoint).

Solutions

  1. Pass the original Config reference when calling rebound_for_model_protocol instead of None
  2. Retain the Config for the client's lifetime if mid-session model switching is expected
  3. Pick a model that resolves to the same protocol as the current binding, or construct a fresh client for the other protocol
  4. If a fallback chain triggers this, ensure fallback models resolve to compatible protocols or rebuild the client at fallback time with the config available

Example fix

// before
let rebound = client.rebound_for_model_protocol(None, "claude-sonnet-4")?;

// after
let rebound = client.rebound_for_model_protocol(Some(&config), "claude-sonnet-4")?;
Defensive patterns

Strategy: fallback

Validate before calling

// Before switching models mid-session, confirm the target protocol is reachable:
let candidate = client.resolve_model_route(model)?;
let cross_protocol = candidate.protocol() != client.wire_format;
if cross_protocol && config.is_none() {
    eprintln!("model {model} needs a protocol rebind; keep Config alive or pick a same-protocol model");
}

Try / catch

match client.rebound_for_model_protocol(config.as_ref(), &model) {
    Ok(Some(rebound)) => { /* use rebound */ }
    Ok(None) => { /* current binding already exact */ }
    Err(e) if e.to_string().contains("no configuration is available") => {
        // retain/restore Config and retry, or reject the model switch with a clear user message
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling rebound_for_model_protocol(config=None, model=...) where the resolved route for `model` uses a different protocol than self.wire_format (e.g. an AnthropicMessages-bound client asked for a ChatCompletions model). The same-protocol path (client.rs:1805) succeeds without config; only cross-protocol switches hit this error.

Common situations: Embedded or test runtimes that construct a model-aware client and drop the original Config before switching models; switching to a fallback model that lives on a provider with a different wire protocol; a route/mid-session model change in a runtime that never retained Config.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/72339b894f765109. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/client.rs:1817

        if candidate.protocol() == self.wire_format
            && candidate.wire_model_id().as_str() == self.default_model
            && candidate_limits == self.route_limits
        {
            return Ok(None);
        }
        if candidate.protocol() == self.wire_format {
            // Same-protocol model switches keep the already-authenticated,
            // endpoint-bound transport but must freeze the alternate model's
            // exact wire identity and limits. This path is also what makes a
            // model-aware client usable in embedded/test runtimes that do not
            // retain the original Config after construction.
            let mut rebound = self.clone();
            rebound.default_model = candidate.wire_model_id().as_str().to_string();
            rebound.route_limits = candidate_limits;
            return Ok(Some(rebound));
        }
        let config = config.ok_or_else(|| {
            anyhow::anyhow!(
                "{} model {:?} uses {:?}, but this client is bound to {:?} and no configuration is available to rebuild it",
                self.api_provider.display_name(),
                model,
                candidate.protocol(),
                self.wire_format
            )
        })?;
        let mut rebound = Self::from_candidate(config, &candidate)?;
        rebound.configured_models = Arc::clone(&self.configured_models);
        Ok(Some(rebound))
    }

    fn bind_request_to_protocol(
        &self,
        mut request: MessageRequest,
    ) -> Result<(MessageRequest, Option<RouteLimits>)> {
        let model_aware = self.api_provider.metadata().is_some_and(|provider| {
            provider.wire_policy() == codewhale_config::provider::WirePolicy::ModelAware

View on GitHub (pinned to 73e0f67d83)