nikivdev/code · error

empty recipe selector

Error message

empty recipe selector

What it means

`select_recipe` rejects an empty (or whitespace-only) selector before doing any matching. This is a fast-fail input validation so callers get a precise message instead of a confusing 'no recipe matched' result.

Source

Thrown at src/recipe.rs:620

            let mut hay = String::new();
            hay.push_str(&r.id);
            hay.push(' ');
            hay.push_str(&r.name);
            hay.push(' ');
            hay.push_str(&r.description);
            if !r.tags.is_empty() {
                hay.push(' ');
                hay.push_str(&r.tags.join(" "));
            }
            hay.to_ascii_lowercase().contains(&needle)
        })
        .collect()
}

fn select_recipe<'a>(recipes: &'a [Recipe], selector: &str) -> Result<&'a Recipe> {
    let normalized = selector.trim();
    if normalized.is_empty() {
        bail!("empty recipe selector")
    }

    if let Some(recipe) = recipes.iter().find(|r| r.id == normalized) {
        return Ok(recipe);
    }

    let lowered = normalized.to_ascii_lowercase();
    let exact_name: Vec<&Recipe> = recipes
        .iter()
        .filter(|r| r.name.to_ascii_lowercase() == lowered)
        .collect();
    if exact_name.len() == 1 {
        return Ok(exact_name[0]);
    }
    if exact_name.len() > 1 {
        ambiguous_selector_error(selector, &exact_name)?;
        bail!("ambiguous recipe selector")
    }

View on GitHub (pinned to a747e741ae)

Solutions

  1. Pass a non-empty recipe id on the command line
  2. In scripts, guard the variable: error out early if it is empty before invoking the tool
  3. List recipes first to pick a valid id
  4. Trim/validate user input before forwarding it as the selector

Example fix

# before
SEL=""; f recipe run "$SEL"   # empty recipe selector
# after
[ -n "$SEL" ] || { echo "usage: run.sh <recipe-id>"; exit 2; }
f recipe run "$SEL"
Defensive patterns

Strategy: validation

Validate before calling

// preflight: reject empty selector before invoking the CLI
fn require_selector(arg: Option<&str>) -> Result<String, String> {
    arg.map(str::trim)
        .filter(|s| !s.is_empty())
        .map(str::to_string)
        .ok_or_else(|| "recipe id required: pass a non-empty <recipe-id>".to_string())
}

Type guard

fn has_selector(args: &[String]) -> bool {
    args.get(1).map_or(false, |s| !s.trim().is_empty())
}

Try / catch

match run() {
    Err(e) if e.to_string().contains("empty recipe selector") => {
        eprintln!("usage: f recipe run <recipe-id>");
        std::process::exit(2);
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling `run_recipe` with `RecipeRunOpts.selector` set to "" or only whitespace — typically an unset/empty shell variable or an argument accidentally dropped from the command line.

Common situations: Unset environment variable interpolated into the command (`f recipe run "$SEL"`); scripted invocation where an argument was conditional and omitted; piping a name with only spaces due to a parsing bug.

Related errors


AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01). Data as JSON: /api/errors/cf4b48561095ff32. Report an issue: GitHub.