aaif-goose/goose · error

Invalid provider id: provider id cannot be empty

Error message

Invalid provider id: provider id cannot be empty

What it means

goose derives a provider id from a display name (generate_id) and validates it with validate_provider_id. The id must be non-empty and start with an ASCII lowercase letter, digit, or underscore. This variant is returned when the candidate id is the empty string — usually a display name that produced no usable characters after slug generation.

Source

Thrown at crates/goose/src/config/declarative_providers.rs:100

        .to_string();
    let base_id = format!("custom_{}", normalized);

    let custom_dir = custom_providers_dir();
    let mut candidate_id = base_id.clone();
    let mut counter = 1;

    while custom_dir.join(format!("{}.json", candidate_id)).exists() {
        candidate_id = format!("{}_{}", base_id, counter);
        counter += 1;
    }

    candidate_id
}

pub fn validate_provider_id(id: &str) -> Result<()> {
    let mut chars = id.chars();
    let Some(first) = chars.next() else {
        return Err(anyhow::anyhow!(
            "Invalid provider id: provider id cannot be empty"
        ));
    };

    if !(first.is_ascii_lowercase() || first.is_ascii_digit() || first == '_') {
        return Err(anyhow::anyhow!("Invalid provider id: {}", id));
    }

    if chars.all(|ch| ch.is_ascii_lowercase() || ch.is_ascii_digit() || ch == '_' || ch == '-') {
        Ok(())
    } else {
        Err(anyhow::anyhow!("Invalid provider id: {}", id))
    }
}

fn custom_provider_file_path(id: &str) -> Result<PathBuf> {
    if id.is_empty()
        || id

View on GitHub (pinned to 3810898a74)

Solutions

  1. Provide a display_name containing at least one ASCII letter or digit (e.g. "Acme Gateway")
  2. If scripting, assert the display-name variable is non-empty and has an alphanumeric before calling create_custom_provider

Example fix

// before
let params = CreateCustomProviderParams { display_name: String::new(), ..Default::default() };
create_custom_provider(params)?;

// after
let params = CreateCustomProviderParams { display_name: "acme-gateway".into(), ..Default::default() };
create_custom_provider(params)?;
Defensive patterns

Strategy: validation

Validate before calling

// before create_custom_provider:
let candidate = generate_id(&params.display_name);
assert!(!candidate.is_empty(), "display name must yield a non-empty id");

Type guard

fn is_valid_provider_id(id: &str) -> bool {
    let mut chars = id.chars();
    matches!(chars.next(), Some(c) if c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_')
        && chars.all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_' || c == '-')
}

Prevention

When it happens

Trigger: Calling create_custom_provider with a display_name that is empty or contains only characters generate_id strips (spaces, punctuation), so the generated candidate id is "" and validate_provider_id fails on the first chars().next().

Common situations: Creating a custom provider named "---" or whitespace in the desktop UI; a script passing an unset/empty environment variable as display_name.

Related errors


AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16). Data as JSON: /api/errors/e1436679302fb45d. Report an issue: GitHub.