sigoden/aichat · error · anyhow::Error

. Usage

Error message

{err}. Usage: {}

What it means

In src/config/mod.rs macro-argument handling, `macro_value.resolve_variables(&new_args)` failed while expanding `$1`-style variables in macro arguments. The library wraps the underlying error with the macro's usage string: `{err}. Usage: {}` so the caller sees how to invoke it correctly.

Solutions

  1. Follow the printed `Usage:` line exactly — it shows required arguments/variables.
  2. Quote arguments containing spaces: `llm --macro summarize "long text here"`.
  3. Check the macro definition (`$1`, `$2`, flags) and supply every declared variable.
  4. On Windows, mind path backslash/quote handling if the macro expects raw text.

Example fix

// before
llm --macro translate
Error: missing variable $1. Usage: translate <text>

// after
llm --macro translate "hello world"
Defensive patterns

Strategy: validation

Validate before calling

// Shell: check argument count against macro usage before invoking
usage=$(llm --macro mymacro 2>&1 | sed -n 's/.*Usage: //p')
[[ $# -ge 1 ]] || { echo "Usage: $usage"; exit 1; }

Try / catch

// Rust
match run_macro(name, args) {
    Err(e) if e.to_string().contains("Usage:") => {
    eprintln!("{e}"); // usage message is embedded — surface it verbatim
    }
    other => other?,
}

Prevention

When it happens

Trigger: Running a macro with arguments that don't satisfy its declared variables (missing required positional args, invalid flag syntax, or text split issues) — resolve_variables returns Err and it's mapped to include `macro_value.usage(name)`.

Common situations: Invoking `llm --macro NAME` with too few arguments; forgetting to quote an argument containing spaces; Windows argument-splitting quirks with `split_args_text`.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of sigoden/aichat@82976d349a (2026-09-09). Data as JSON: /api/errors/9ae9acea99125e1b. Report an issue: GitHub.

Appendix: source

Thrown at src/config/mod.rs:2474

        *self == WorkingMode::Serve
    }
}

#[async_recursion::async_recursion]
pub async fn macro_execute(
    config: &GlobalConfig,
    name: &str,
    args: Option<&str>,
    abort_signal: AbortSignal,
) -> Result<()> {
    let macro_value = Config::load_macro(name)?;
    let (mut new_args, text) = split_args_text(args.unwrap_or_default(), cfg!(windows));
    if !text.is_empty() {
        new_args.push(text.to_string());
    }
    let variables = macro_value
        .resolve_variables(&new_args)
        .map_err(|err| anyhow!("{err}. Usage: {}", macro_value.usage(name)))?;
    let role = config.read().extract_role();
    let mut config = config.read().clone();
    config.temperature = role.temperature();
    config.top_p = role.top_p();
    config.use_tools = role.use_tools().clone();
    config.macro_flag = true;
    config.model = role.model().clone();
    config.role = None;
    config.session = None;
    config.rag = None;
    config.agent = None;
    config.discontinuous_last_message();
    let config = Arc::new(RwLock::new(config));
    config.write().macro_flag = true;
    for step in &macro_value.steps {
        let command = Macro::interpolate_command(step, &variables);
        println!(">> {}", multiline_text(&command));
        run_repl_command(&config, abort_signal.clone(), &command).await?;

View on GitHub (pinned to 82976d349a)