Hmbown/CodeWhale · error

model must not be empty

Error message

model must not be empty

What it means

When a thread-update request includes a `model`, the value must not be whitespace-only/empty. The guard rejects `Some("")` or `Some(" ")` so a thread never ends up with a meaningless model assignment.

Solutions

  1. Pass `None` to leave the model unchanged instead of `Some("")`.
  2. Trim the incoming string and, if empty after trim, drop the field from the request.
  3. Validate the model string against the registry before sending the update.

Example fix

// before
UpdateThreadRequest { model: Some(user_input), .. }

// after
let model = user_input.trim().to_string();
UpdateThreadRequest { model: (!model.is_empty()).then_some(model), .. }
Defensive patterns

Strategy: validation

Validate before calling

let model = req.model.as_deref().map(str::trim).filter(|m| !m.is_empty());

Type guard

fn valid_model_field(m: &Option<String>) -> bool {
    m.as_deref().map_or(true, |s| !s.trim().is_empty())
}

Prevention

When it happens

Trigger: Calling update-thread with `model: Some("".into())` or `Some(" \t".into())`; a client form submitted with the model field cleared but still serialized as an empty string.

Common situations: An UI clears the model dropdown and sends "" instead of `null`; a config export round-trip loses the model value; JSON body `{"model": ""}` from an API consumer.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

        let _config_admission = self.config_admission.read().await;
        if req.archived.is_none()
            && req.allow_shell.is_none()
            && req.trust_mode.is_none()
            && req.auto_approve.is_none()
            && req.model.is_none()
            && req.mode.is_none()
            && req.permission_posture.is_none()
            && req.title.is_none()
            && req.system_prompt.is_none()
            && req.workspace.is_none()
        {
            bail!("At least one thread field is required");
        }

        if let Some(model) = req.model.as_ref()
            && model.trim().is_empty()
        {
            bail!("model must not be empty");
        }
        if let Some(mode) = req.mode.as_ref()
            && mode.trim().is_empty()
        {
            bail!("mode must not be empty");
        }
        if let Some(permission_posture) = req.permission_posture.as_ref()
            && permission_posture.trim().is_empty()
        {
            bail!("permission_posture must not be empty");
        }
        if let Some(workspace) = req.workspace.as_ref()
            && workspace.as_os_str().is_empty()
        {
            bail!("workspace must not be empty");
        }

        // Source resolution reads config files. Do it off the Tokio worker,

View on GitHub (pinned to 73e0f67d83)