Hmbown/CodeWhale · error

A pinned task provider requires an explicit model

Error message

A pinned task provider requires an explicit model

What it means

When a NewTaskRequest pins a provider (model_provider or model_provider_id set), the request must also name an explicit model. The worker projects runtime policy with a concrete model, so an ambiguous provider-only request is refused at admission rather than failing later after the task sat in the durable queue.

Solutions

  1. Set req.model to a concrete model name whenever req.model_provider/model_provider_id is set
  2. Clear the provider fields if the intent is to use the default provider/model resolution
  3. Validate the (provider, model) pair in the caller/UI before submitting the request
  4. Ensure templates/config migrations that add a provider also carry a model

Example fix

// before
let req = NewTaskRequest { model_provider: Some("openai"), model: None, .. };
// after
let req = NewTaskRequest {
    model_provider: Some("openai"),
    model: Some("gpt-4o".into()),
    ..
};
Defensive patterns

Strategy: validation

Validate before calling

anyhow::ensure!(req.model_provider.is_none() && req.model_provider_id.is_none() || req.model.as_deref().map_or(false, |m| !m.trim().is_empty()), "pinned provider needs an explicit model");

Prevention

When it happens

Trigger: Calling add_task_with_id with model_provider/model_provider_id set but model None or empty/whitespace after trim.

Common situations: Automation rules that pin a provider but forget the model field; UI state where the model selector was cleared but the provider persisted; config templates carrying provider-only overrides.

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/1879009f101d263a. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/task_manager.rs:1687

    /// Enqueue using a preallocated id. This is crate-visible only for the
    /// model tool's register-before-work transaction.
    pub(crate) async fn add_task_with_id(
        &self,
        req: NewTaskRequest,
        task_id: String,
    ) -> Result<TaskRecord> {
        let prompt = req.prompt.trim().to_string();
        if prompt.is_empty() {
            bail!("Task prompt cannot be empty");
        }
        if (req.model_provider.is_some() || req.model_provider_id.is_some())
            && req
                .model
                .as_deref()
                .is_none_or(|model| model.trim().is_empty())
        {
            bail!("A pinned task provider requires an explicit model");
        }
        // The worker runs this same projection when it opens the task's
        // thread. Running it here as well refuses an unknown mode or posture
        // at the boundary the request crossed, instead of after the task has
        // sat in the durable queue and a worker has claimed it.
        crate::runtime_policy::RuntimePolicyProjection::from_request(
            req.mode
                .as_deref()
                .filter(|mode| !mode.trim().is_empty())
                .unwrap_or(&self.cfg.default_mode),
            req.permission_posture.as_deref(),
            req.auto_approve,
        )?;
        validate_preallocated_task_id(&task_id)?;

        let task = TaskRecord {
            schema_version: CURRENT_TASK_SCHEMA_VERSION,
            // 16 random hex chars (was 8; ~60 bits of entropy once UUIDv4's

View on GitHub (pinned to 73e0f67d83)