{"record":{"id":"5915350f6e22808e","repo":"aaif-goose/goose","slug":"invalid-provider-id","errorCode":null,"errorMessage":"Invalid provider id: {}","messagePattern":"Invalid provider id: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose/src/config/declarative_providers.rs","lineNumber":106,"sourceCode":"\n    while custom_dir.join(format!(\"{}.json\", candidate_id)).exists() {\n        candidate_id = format!(\"{}_{}\", base_id, counter);\n        counter += 1;\n    }\n\n    candidate_id\n}\n\npub fn validate_provider_id(id: &str) -> Result<()> {\n    let mut chars = id.chars();\n    let Some(first) = chars.next() else {\n        return Err(anyhow::anyhow!(\n            \"Invalid provider id: provider id cannot be empty\"\n        ));\n    };\n\n    if !(first.is_ascii_lowercase() || first.is_ascii_digit() || first == '_') {\n        return Err(anyhow::anyhow!(\"Invalid provider id: {}\", id));\n    }\n\n    if chars.all(|ch| ch.is_ascii_lowercase() || ch.is_ascii_digit() || ch == '_' || ch == '-') {\n        Ok(())\n    } else {\n        Err(anyhow::anyhow!(\"Invalid provider id: {}\", id))\n    }\n}\n\nfn custom_provider_file_path(id: &str) -> Result<PathBuf> {\n    if id.is_empty()\n        || id\n            .chars()\n            .any(|ch| ch == '/' || ch == '\\\\' || ch.is_control())\n    {\n        return Err(anyhow::anyhow!(\n            \"Invalid provider id: {}\",\n            if id.is_empty() { \"<empty>\" } else { id }","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose/src/config/declarative_providers.rs#L88-L124","documentation":"validate_provider_id enforces that a provider id starts with an ASCII lowercase letter, digit, or underscore. This variant is returned when the id is non-empty but its FIRST character violates that rule (uppercase letter, hyphen, dot, space, or any other symbol).","triggerScenarios":"Passing an id like \"-acme\", \"OpenAI\", \".local\", or \" acme\" to validate_provider_id, or a display name whose slugified form begins with a hyphen (e.g. \"- Acme Gateway\") so generate_id yields a leading '-'.","commonSituations":"Hand-editing custom provider ids; provider ids copied from vendor names that start uppercase; script-generated ids that prefix a separator.","solutions":["Make the id start with a lowercase letter, digit, or underscore (rename \"-acme\" to \"acme\" or \"_acme\")","Give the display name a leading alphanumeric word so the generated slug starts clean"],"exampleFix":"// before\nvalidate_provider_id(\"-acme\")?;\n\n// after\nvalidate_provider_id(\"acme\")?;","handlingStrategy":"validation","validationCode":"fn first_char_ok(id: &str) -> bool {\n    id.chars().next().is_some_and(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_')\n}","typeGuard":"fn is_valid_provider_id(id: &str) -> bool {\n    let mut chars = id.chars();\n    matches!(chars.next(), Some(c) if c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_')\n        && chars.all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_' || c == '-')\n}","tryCatchPattern":null,"preventionTips":["Normalize ids to lowercase before validation","Strip leading separators/spaces from display names before slug generation"],"tags":["providers","validation","custom-providers","id"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}