jdx/mise · error · eyre::Report
expected closing parenthesis
Error message
expected closing parenthesis
What it means
mise requires that any cask containing pkg artifacts also declares pkgutil receipt ids in its uninstall metadata, mirroring Homebrew's own rule — without pkgutil ids there is no way to track or uninstall an installed pkg. After dedup, if pkgs is non-empty but pkg_ids is empty, the install aborts.
Source
Thrown at crates/aqua-registry/src/template.rs:244
Ok(left)
}
/// Parse primary expressions
fn parse_primary(tokens: &mut std::iter::Peekable<std::slice::Iter<Token>>) -> Result<Expr> {
skip_whitespace(tokens);
let token = tokens.next().wrap_err("unexpected end of expression")?;
let expr = match token {
Token::Key(k) => Expr::Var(k.to_string()),
Token::String(s) => Expr::Literal(s.to_string()),
Token::LParen => {
// Parenthesized expression: (func arg)
skip_whitespace(tokens);
let inner = parse_pipe(tokens)?;
skip_whitespace(tokens);
if !matches!(tokens.next(), Some(Token::RParen)) {
bail!("expected closing parenthesis");
}
inner
}
Token::Func(f) => {
// Function call: func arg1 arg2
let func_name = f.to_string();
let mut args = Vec::new();
// Collect arguments until we hit pipe, rparen, or end
loop {
skip_whitespace(tokens);
match tokens.peek() {
None | Some(Token::Pipe) | Some(Token::RParen) => break,
Some(Token::Dot) | Some(Token::Ident(_)) => break, // Stop before property access
_ => {
args.push(parse_arg(tokens)?);
}View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- If you maintain the cask, add the pkg's receipt id to the uninstall stanza (get it via pkgutil --pkgs or the pkg's Distribution file)
- Install with upstream brew, which may have looser handling, and report the cask to its tap
- Update mise in case newer metadata from the API resolves the mismatch
Example fix
# cask JSON
# before
{"artifacts": [{"pkg": ["Installer.pkg"]}], "uninstall": {}}
# after
{"artifacts": [{"pkg": ["Installer.pkg"]}], "uninstall": {"pkgutil": ["com.example.installer"]}} Defensive patterns
Strategy: validation
Validate before calling
let has_pkg = artifacts.iter().any(|a| artifact_type(a) == "pkg");
let has_pkgutil = cask.uninstall.pkgutil.is_some_and(|ids| !ids.is_empty());
if has_pkg && !has_pkgutil { /* reject the cask before install */ } Prevention
- Always pair pkg stanzas with uninstall pkgutil ids when authoring casks
- Run brew audit / cask linters on third-party casks before use
When it happens
Trigger: Cask JSON with a 'pkg' artifact but no uninstall: {pkgutil: [...]} entry; uninstall metadata listing only delete/quit entries while a pkg stanza exists.
Common situations: Hand-written casks missing the uninstall stanza; third-party taps with incomplete casks; upstream cask lint rules normally catch this, so it usually means non-canonical metadata.
Related errors
- install from exe
- mise outdated --monorepo is not implemented yet
- mise prune --monorepo is not implemented yet
- mise upgrade --monorepo is not implemented yet
- erlang does not yet support refs
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/f6208f74bbb2a7c5.
Report an issue: GitHub.