{"record":{"id":"107003a966f9ff14","repo":"jdx/mise","slug":"invalid-system-package-spec-spec-expected-m","errorCode":null,"errorMessage":"invalid system package spec '{spec}': expected '<manager>:<package>' (e.g. \"apt:curl\")","messagePattern":"invalid system package spec '(.+?)': expected '<manager>:<package>' \\(e\\.g\\. \"apt:curl\"\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/mod.rs","lineNumber":361,"sourceCode":"    BrewCask { adopt: BTreeSet<String> },\n}\n\nimpl ManagerPackageOptions {\n    #[cfg(unix)]\n    pub(crate) fn brew_cask_adopt(&self, name: &str) -> bool {\n        matches!(self, Self::BrewCask { adopt } if adopt.contains(name))\n    }\n}\n\n/// Split a `\"manager:package\"` spec (config key or CLI argument). Only the\n/// first `:` separates — apt arch qualifiers (\"apt:gcc:arm64\") and brew\n/// versioned formula names (\"brew:postgresql@17\") stay part of the package.\npub(crate) fn parse_spec(spec: &str) -> eyre::Result<(String, String)> {\n    match spec.split_once(':') {\n        Some((mgr, pkg)) if !mgr.is_empty() && !pkg.is_empty() => {\n            Ok((mgr.to_string(), pkg.to_string()))\n        }\n        _ => bail!(\n            \"invalid system package spec '{spec}': expected '<manager>:<package>' (e.g. \\\"apt:curl\\\")\"\n        ),\n    }\n}\n\n/// Split a `mise bootstrap packages use` spec `manager:package[@version]` into its parts.\n///\n/// `@version` mirrors `mise use tool@version`; `@latest` (or no `@`) means no\n/// pin. brew and brew-cask are exempt from `@` parsing: `@` is part of\n/// Homebrew names (`postgresql@17` — that name IS brew's versioning\n/// mechanism), and bottles/casks can't be installed at a pinned version\n/// anyway. mas uses numeric ADAM IDs only.\npub(crate) fn parse_use_spec(spec: &str) -> eyre::Result<(String, PackageRequest)> {\n    let (mgr, rest) = parse_spec(spec)?;\n    let rest = normalize_use_spec_package_name(&mgr, &rest)?;\n    validate_package_name(&mgr, rest)?;\n    if is_opaque_package_manager(&mgr) {\n        return Ok((","sourceCodeStart":343,"sourceCodeEnd":379,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/mod.rs#L343-L379","documentation":"parse_spec parses a system package spec for `mise bootstrap packages` and requires the strict form `<manager>:<package>`. It bails when the spec has no colon at all, or the colon exists but the manager or package side is empty. Versioned names like brew:postgresql@17 keep the whole remainder as the package name.","triggerScenarios":"Passing a string without a `manager:` prefix (e.g. \"curl\" instead of \"apt:curl\"), an empty manager (\":curl\"), or an empty package (\"apt:\"), via parse_use_spec, package_requests_from_config_files, or packages_from_specs_with_config.","commonSituations":"Forgetting the manager prefix in mise.toml [packages] entries or on the `mise bootstrap packages use` command line; copying a plain OS package name from apt/brew docs; a config file line like curl = true instead of apt:curl.","solutions":["Prefix the spec with the package manager: \"apt:curl\", \"brew:ripgrep\", \"mas:Xcode\"","Fix empty manager or package parts in your config or CLI arg (\":curl\" -> \"apt:curl\", \"apt:\" -> \"apt:curl\")","For config files, ensure every entry is in manager:package form"],"exampleFix":"// before (mise.toml or CLI)\n//   mise bootstrap packages use curl\n// after\n//   mise bootstrap packages use apt:curl","handlingStrategy":"validation","validationCode":"// Validate a system package spec before passing it to mise:\nfunction isValidPackageSpec(spec: string): boolean {\n  const i = spec.indexOf(\":\");\n  if (i <= 0 || i === spec.length - 1) return false;\n  return !spec.slice(0, i).includes(\":\") && spec.slice(i + 1).length > 0;\n}\n// isValidPackageSpec(\"apt:curl\") === true; isValidPackageSpec(\"curl\") === false","typeGuard":"function isManagerPrefixed(s: string): s is `${string}:${string}` {\n  const i = s.indexOf(\":\");\n  return i > 0 && i < s.length - 1;\n}","tryCatchPattern":"try {\n  await mise([\"bootstrap\", \"packages\", \"use\", spec]);\n} catch (e) {\n  if (String(e).includes(\"expected '<manager>:<package>'\")) {\n    throw new Error(`Spec \"${spec}\" needs a manager prefix, e.g. apt:${spec}`);\n  }\n  throw e;\n}","preventionTips":["Always write manager:package form in configs and CLI args (apt:curl, brew:ripgrep)","Lint mise.toml [packages] entries for a colon before the package name","Copy specs from `mise bootstrap packages --help` examples, not raw OS package names","Remember versioned names stay intact: brew:postgresql@17"],"tags":["cli","config","parsing","system-packages"],"backgroundTag":"invalid-argument-format","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}