{"record":{"id":"a5649bd8b2d6aaaf","repo":"Hmbown/CodeWhale","slug":"agent-profile-provider-cannot-be-empty","errorCode":null,"errorMessage":"agent profile {} provider cannot be empty","messagePattern":"agent profile (.+?) provider cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/fleet/profile.rs","lineNumber":500,"sourceCode":"        bail!(\n            \"agent profile {} model must be a visible model id without whitespace or secrets\",\n            path.display()\n        );\n    }\n    Ok(())\n}\n\n/// Validate an explicit `provider` field as a safe provider id (#4093).\n///\n/// Built-in providers are accepted by the runtime vocabulary, and user-named\n/// OpenAI-compatible custom providers are accepted as simple tokens so the\n/// launch path can resolve `[providers.<id>]` from the session config (#3965).\n/// This field remains the ONLY place a profile's provider is established:\n/// callers never infer it from `model` (EPIC #2608).\nfn validate_agent_profile_provider(path: &Path, value: &str) -> Result<()> {\n    let trimmed = value.trim();\n    if trimmed.is_empty() {\n        bail!(\"agent profile {} provider cannot be empty\", path.display());\n    }\n    if trimmed != value || !trimmed.chars().all(is_agent_profile_token_char) {\n        bail!(\n            \"agent profile {} provider must be a simple provider id\",\n            path.display()\n        );\n    }\n    Ok(())\n}\n\nfn normalize_agent_profile_reasoning_effort(\n    path: &Path,\n    value: Option<&str>,\n) -> Result<Option<String>> {\n    let Some(value) = non_empty_trimmed(value) else {\n        return Ok(None);\n    };\n    if matches!(","sourceCodeStart":482,"sourceCodeEnd":518,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/fleet/profile.rs#L482-L518","documentation":"validate_agent_profile_provider rejects a provider value that is empty after trimming. The provider field is the only place a profile establishes its provider (callers never infer it from model), and it must resolve to a built-in provider or a [providers.<id>] entry in the session config, so a blank value is refused rather than defaulted.","triggerScenarios":"A provider field that reaches validation as \"\" or whitespace-only. The file loader drops blank provider values before validating, so in practice this surfaces from the drafted/programmatic profile paths that run the validator directly on constructed values.","commonSituations":"A model-drafted or scripted profile emitting provider = \"\" because the user left the provider unset; serialization code that writes an empty provider key instead of omitting it.","solutions":["Remove the provider key entirely when no explicit provider is intended - the launch path then resolves it from session config","Or set a real provider id: provider = \"anthropic\" or your custom [providers.<id>] key","If generating profiles programmatically, skip the field when the value would be blank instead of writing an empty string"],"exampleFix":"# before\nprovider = \"\"\n\n# after\nprovider = \"anthropic\"\n# or omit the key entirely","handlingStrategy":"validation","validationCode":"fn provider_or_none(value: Option<&str>) -> Option<&str> {\n    value.map(str::trim).filter(|v| !v.is_empty())\n}\n// serialize Option::None (skip the key) instead of Some(\"\"), and validate before load","typeGuard":"fn is_valid_provider(value: &str) -> bool {\n    let t = value.trim();\n    !t.is_empty()\n        && t.chars().all(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_' | '.'))\n}","tryCatchPattern":"match load_agent_profile_file(&path) {\n    Ok(p) => Ok(p),\n    Err(err) if err.to_string().contains(\"provider cannot be empty\") => {\n        Err(anyhow!(\"profile {path:?}: drop the provider key or set a real provider id\"))\n    }\n    Err(err) => Err(err),\n}","preventionTips":["Omit the provider key when unset instead of writing an empty string","Run drafted/programmatic profiles through the same trim-then-validate pipeline as file loads","Default provider resolution to session config rather than blank profile values"],"tags":["agent-profile","provider","toml","validation","fleet"],"backgroundTag":"empty-required-field","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}