{"record":{"id":"6d97ed3b5f011517","repo":"Hmbown/CodeWhale","slug":"provider-authority-checked-above","errorCode":null,"errorMessage":"provider authority checked above","messagePattern":"provider authority checked above","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/fleet/worker_runtime.rs","lineNumber":299,"sourceCode":"        let explicit_provider = explicit_fleet_provider_id(agent_profile);\n        if config.is_none() && explicit_provider.is_none() {\n            bail!(\n                \"Fleet task `{}` has no provider authority for model `{model}` (source={source}); attach the resolved route config or set the agent profile provider explicitly\",\n                task.id,\n            );\n        }\n        if config.is_none()\n            && let Some(provider_id) = explicit_provider.as_deref()\n            && ApiProvider::parse(provider_id)\n                .is_none_or(|provider| provider == ApiProvider::Custom)\n        {\n            bail!(\n                \"Fleet task `{}` names custom provider=`{provider_id}`, but a provider name alone does not prove its endpoint or model; attach the live route config before creating the run\",\n                task.id,\n            );\n        }\n        if pinned_model && explicit_provider.is_none() {\n            let config = config.expect(\"provider authority checked above\");\n            let (provider, base_url) = (config.api_provider(), config.deepseek_base_url());\n            if let Err(reason) =\n                crate::route_runtime::validate_unpinned_model_provider(provider, &model, &base_url)\n            {\n                bail!(\"Fleet task `{}`: {reason} (source={source})\", task.id);\n            }\n        }\n\n        let route = resolve_fleet_route_with_config(task, agent_profiles, session_model, config);\n        let provider = explicit_provider\n            .map(|provider| format!(\"provider=`{provider}`\"))\n            .unwrap_or_else(|| {\n                \"no explicit provider (resolves against the session/default provider)\".to_string()\n            });\n        if route.is_none() {\n            if pinned_model {\n                bail!(\n                    \"Fleet task `{}` pins model `{}` with {} (source={source}), but that route does not \\","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/crates/tui/src/fleet/worker_runtime.rs#L281-L317","documentation":"An internal invariant assertion in `validate_fleet_task_routes`: when a task pins a model without naming an explicit provider, the code expects `config` to be `Some` because earlier branches already handled the explicit-provider cases. The expect fires only if the preceding provider-authority logic and this assumption drift out of sync — i.e. a model pin reached this line with `config == None` despite the checks above.","triggerScenarios":"Adding or modifying the earlier bail!/match arms in `validate_fleet_task_routes` so a pinned-model task with no explicit provider and no live config falls through to this line; calling validation with configless routes in a way the earlier checks do not cover (e.g. a new pin syntax or provider-inheritance shape).","commonSituations":"Refactors of fleet route validation, new task-route fields that skip the explicit-provider check, regression tests introducing pinned models without attaching route config.","solutions":["Re-read the branches above the expect and restore the invariant that pinned_model && explicit_provider.is_none() implies config is Some","Handle the configless pinned-model case explicitly with a bail! instead of expecting","Add a test covering the new route shape that reaches this line","Replace expect with `let Some(config) = config else { bail!(...) }` so a violated invariant produces a diagnosable error, not a panic"],"exampleFix":"// before\nlet config = config.expect(\"provider authority checked above\");\n// after\nlet config = config.ok_or_else(|| {\n    anyhow::anyhow!(\"Fleet task `{}` pins model `{model}` without a live route config\", task.id)\n})?;","handlingStrategy":"type-guard","validationCode":"// rust, caller-side check before validation\nif task.model.is_some() && task.provider.is_none() && route_config.is_none() {\n    return Err(anyhow!(\"task {} pins a model without a route config\", task.id));\n}","typeGuard":"// rust\nlet config = match config {\n    Some(c) => c,\n    None => return Err(anyhow!(\"pinned model requires live route config\")),\n};","tryCatchPattern":"// rust\nmatch validate_fleet_task_routes(&tasks, source, config) {\n    Ok(()) => {},\n    Err(e) => eprintln!(\"fleet route validation failed: {e}\"),\n}","preventionTips":["When editing validation branches, re-check which invariants later code relies on","Prefer let-else/bail! over expect for config-dependent invariants","Cover every route shape (pinned/unpinned × provider/no-provider) with tests"],"tags":["rust","panic","invariant","fleet","config"],"backgroundTag":"internal-invariant-violation","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}