Hmbown/CodeWhale · error

image inputs require an exact named model with supported…

Error message

image inputs require an exact named model with supported image input; Auto is unavailable for images

What it means

Codewhale's runtime turn handler refuses to start a turn that includes image (attachment) blocks unless the request names a concrete model. The special model value "auto" (and empty/whitespace-padded names) trigger dynamic model routing, which cannot guarantee image-input capability, so it is rejected up front with this error.

Solutions

  1. Set req.model to an exact named model that supports image input (capabilities.image_input == Supported).
  2. Remove the image blocks from the request if Auto routing is required.
  3. Check the resolved route's capabilities via resolve_runtime_thread_route_for_identity before sending images.

Example fix

// before
let req = ThreadTurnRequest { model: "auto".into(), prompt: prompt_with_screenshot, ..Default::default() };
// after
let req = ThreadTurnRequest { model: "claude-sonnet-4".into(), prompt: prompt_with_screenshot, ..Default::default() };
Defensive patterns

Strategy: validation

Validate before calling

fn can_send_images(req: &ThreadTurnRequest, thread: &Thread) -> bool {
    let model = req.model.as_deref().unwrap_or(&thread.model).trim();
    !model.is_empty() && !model.eq_ignore_ascii_case("auto")
}

Type guard

fn is_exact_model(model: &str) -> bool { !model.trim().is_empty() && !model.trim().eq_ignore_ascii_case("auto") }

Prevention

When it happens

Trigger: Calling the runtime turn API (ThreadTurnRequest) with a prompt containing image content blocks while req.model (or the thread's model) is set to "auto" (case-insensitive).

Common situations: Developers leaving the model selector on Auto/default while pasting a screenshot into the chat; programmatic clients omitting `model` when sending attachments; UI code that resolves "auto" to a routing placeholder before dispatch.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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

Appendix: source

Thrown at crates/tui/src/runtime_threads.rs:9861

                    req.mode.as_deref(),
                    req.permission_posture.as_deref(),
                    req.auto_approve,
                )?
            } else {
                RuntimePolicyProjection::from_persisted(
                    &thread.mode,
                    thread.permission_posture.as_deref(),
                    thread.auto_approve,
                )
            };
        let mode = policy.mode;
        let requested_model = req.model.as_deref().unwrap_or(&thread.model).to_string();
        let auto_model = requested_model.trim().eq_ignore_ascii_case("auto");
        if !image_blocks.is_empty() && (requested_model.is_empty() || requested_model.trim() != requested_model) {
            bail!("image inputs require an exact nonempty named model");
        }
        if !image_blocks.is_empty() && auto_model {
            bail!("image inputs require an exact named model with supported image input; Auto is unavailable for images");
        }
        let cfg_snapshot = self.config.read().clone();
        let configured_reasoning_preference = cfg_snapshot
            .reasoning_effort()
            .map(crate::reasoning_preference::ReasoningEffort::from_setting);
        // Runtime API precedence is explicit and stable: a turn override wins
        // over its persisted thread default, which wins over normal config.
        let reasoning_preference = turn_reasoning_preference
            .or(thread_reasoning_preference)
            .or(configured_reasoning_preference);
        let allow_shell = req.allow_shell.unwrap_or(thread.allow_shell);
        let trust_mode = req.trust_mode.unwrap_or(thread.trust_mode);
        let auto_approve = policy.auto_approve();
        let allowed_tools = req
            .allowed_tools
            .clone()
            .or_else(|| thread.allowed_tools.clone());
        if req.max_output_tokens.is_some() && auto_model {

View on GitHub (pinned to 73e0f67d83)