{"record":{"id":"5f60b9aca66f9c4e","repo":"jdx/mise","slug":"mise-link-only-supports-concrete-versions-and-refs","errorCode":null,"errorMessage":"mise link only supports concrete versions and refs, not {}","messagePattern":"mise link only supports concrete versions and refs, not (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cli/link.rs","lineNumber":38,"sourceCode":"    /// Tool name and version to create a symlink for\n    #[clap(value_name = \"TOOL@VERSION\")]\n    tool: ToolArg,\n\n    /// The local path to the tool version\n    /// e.g.: ~/.nvm/versions/node/v20.0.0\n    #[clap(value_hint = ValueHint::DirPath, verbatim_doc_comment)]\n    path: PathBuf,\n\n    /// Overwrite an existing tool version if it exists\n    #[clap(long, short = 'f')]\n    force: bool,\n}\n\nimpl Link {\n    pub async fn run(self) -> Result<()> {\n        let tvr = match self.tool.tvr.as_ref() {\n            Some(tvr @ (ToolRequest::Version { .. } | ToolRequest::Ref { .. })) => tvr,\n            Some(tvr) => bail!(\n                \"mise link only supports concrete versions and refs, not {}\",\n                tvr.version()\n            ),\n            None => bail!(\"must provide a version for {}\", self.tool.style()),\n        };\n        let config = Config::get().await?;\n        let version_pathname = match tvr {\n            ToolRequest::Version { version, .. } => {\n                let backend = tvr.backend()?;\n                let resolved_alias = config.resolve_alias(&backend, version).await?;\n                if version == \"latest\"\n                    || resolved_alias != *version\n                    || backend.is_rolling_channel(version)\n                {\n                    bail!(\n                        \"mise link only supports concrete versions and refs, not {}\",\n                        tvr.version()\n                    );","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/cli/link.rs#L20-L56","documentation":"`mise link` creates a symlink from mise's installs directory to an existing tool installation, and can only name the link by a concrete version or a ref. The first guard (link.rs:38) rejects any ToolRequest that is neither `Version` nor `Ref` — e.g. `path:`, `system`, or prefix requests — because there is no stable pathname to link under.","triggerScenarios":"`mise link node@path:/opt/node ~/.tools/node` or `mise link node@20.x ...`; anything where the TOOL@VERSION arg parses into a non-concrete request variant.","commonSituations":"Copy-pasting a version string that works in mise.toml into `mise link`; linking system-managed tools, which link does not support.","solutions":["Provide a concrete version: `mise link node@22.17.1 ~/.tools/node-v22.17.1`","Or a ref: `mise link node@ref:main ~/.tools/node-main`","For versionless aliases, resolve the version first (`mise latest node`) and link that"],"exampleFix":"# before\nmise link node@system /usr\n# after\nmise link node@22.17.1 ~/.tools/node-v22.17.1","handlingStrategy":"validation","validationCode":"#!/usr/bin/env bash\nreq=$1  # expect TOOL@VERSION\nver=${req#*@}\ncase \"$ver\" in\n  \"$req\"|\"\"|path:*|system|ref:*|*.x)\n    echo \"mise link needs a concrete version, e.g. ${req%%@*}@22.17.1\" >&2; exit 2 ;;\nesac\nmise link \"$req\" \"$path\"","typeGuard":null,"tryCatchPattern":"mise link \"$tool@$ver\" \"$path\" 2>err.log || { grep -q 'only supports concrete versions' err.log && mise link \"$tool@$(mise latest \"$tool\")\" \"$path\"; }","preventionTips":["Resolve moving specifiers to concrete versions before linking","Treat link as an explicit-version-only command in scripts"],"tags":["cli","link","version-specifier","mise"],"backgroundTag":"unsupported-version-specifier","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}