jdx/mise · error · eyre::Report
expected identifier after dot
Error message
expected identifier after dot
What it means
A command_wrapper artifact's first array element must be a bare command name: Path::file_name() of the name must equal the whole string and it must not be '.' or '..'. Any '/', trailing separator, or dot-only name is rejected because the name becomes both the staged script name and the symlinked command in bin.
Source
Thrown at crates/aqua-registry/src/template.rs:312
tokens.next();
Ok(Expr::Literal(s.to_string()))
}
_ => Err(eyre!("expected argument")),
}
}
fn parse_property_chain(
tokens: &mut std::iter::Peekable<std::slice::Iter<Token>>,
mut expr: Expr,
) -> Result<Expr> {
while matches!(tokens.peek(), Some(Token::Dot)) {
tokens.next(); // consume dot
skip_whitespace(tokens);
if let Some(Token::Ident(prop)) = tokens.next() {
expr = Expr::PropertyAccess(Box::new(expr), prop.to_string());
} else {
bail!("expected identifier after dot");
}
}
Ok(expr)
}
fn skip_whitespace(tokens: &mut std::iter::Peekable<std::slice::Iter<Token>>) {
while matches!(tokens.peek(), Some(Token::Whitespace(_))) {
tokens.next();
}
}
/// Function signature for template functions that return Value trait objects
type TemplateFn = fn(&[Box<dyn Value>]) -> Result<Box<dyn Value>>;
/// Static registry of available template functions
static FUNCTION_REGISTRY: LazyLock<HashMap<&'static str, TemplateFn>> = LazyLock::new(|| {
let mut registry: HashMap<&'static str, TemplateFn> = HashMap::new();View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Use a plain command name with no path separators ('tool', not 'bin/tool')
- If the executable lives in a subdirectory, put the path in the 'executable' option and keep 'name' bare
Example fix
# command_wrapper artifact
# before
{"command_wrapper": ["bin/my-tool", {"executable": "pkg/bin/tool"}]}
# after
{"command_wrapper": ["my-tool", {"executable": "pkg/bin/tool"}]} Defensive patterns
Strategy: validation
Validate before calling
let p = Path::new(name);
if p.file_name().and_then(|n| n.to_str()) != Some(name) || matches!(name, "." | "..") {
// reject before parse/install
} Type guard
fn is_bare_command_name(name: &str) -> bool {
Path::new(name).file_name().and_then(|n| n.to_str()) == Some(name)
&& !matches!(name, "." | "..")
} Prevention
- Use plain command names for wrappers; put paths in the executable option
- Lint wrapper names for separators in metadata pipelines
When it happens
Trigger: command_wrapper names like 'bin/tool', './tool', 'tool/', 'sub/dir/tool', '.', or '..' in the cask/mise metadata.
Common situations: Authors pasting a relative path into the wrapper name; metadata generators filling the field with a file path instead of a command name.
Related errors
- mise prune --monorepo is not implemented yet
- semver requires exactly 1 argument
- title requires exactly 1 argument
- trimV requires exactly 1 argument
- trimPrefix requires exactly 2 arguments
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/aa135900e5984f33.
Report an issue: GitHub.