{"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":51,"sourceCode":"    /// Tool name and version to create a symlink for\n    #[usage(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    #[usage(value_hint = ValueHint::DirPath, verbatim_doc_comment)]\n    path: PathBuf,\n\n    /// Overwrite an existing tool version if it exists\n    #[usage(long, short = 'f')]\n    force: bool,\n}\n\nimpl Link {\n    pub(crate) 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":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/cli/link.rs#L33-L69","documentation":"This error is thrown by the `mise link` command when the tool argument resolves to a ToolRequest other than a concrete Version or Ref. Linking a local checkout into mise's installs directory requires a concrete version (or ref) to name the install directory; prefix, sub, or latest-style specs cannot be linked.","triggerScenarios":"Running `mise link <tool>@latest`, `mise link <tool>@22`, or any non-version/non-ref spec; also passing no version at all (which throws the adjacent 'must provide a version' bail).","commonSituations":"Users assuming link accepts 'latest' like install does; linking with a prefix version ('22') that resolves to a ToolRequest::Prefix rather than a concrete version; script variables containing 'latest' interpolated into the link command.","solutions":["Pass a concrete version: mise link node 22.3.0 --path /path/to/build","Use a ref form if linking from a source checkout: mise link node@ref:abc123 --path ...","Resolve the version first (e.g. mise ls-remote) and pass the exact version string"],"exampleFix":"// before\nmise link node@latest --path ~/src/node\n// after\nmise link node 22.3.0 --path ~/src/node","handlingStrategy":"validation","validationCode":"SPEC=\"$1\"\nif [[ \"$SPEC\" == \"latest\" || \"$SPEC\" == *\"@latest\" ]]; then\n  echo \"mise link requires a concrete version or ref, not '$SPEC'\" >&2\n  exit 1\nfi","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Resolve concrete versions first (mise ls-remote) before linking","Never interpolate 'latest' or bare prefixes into mise link in scripts","Use ref:<sha> form when linking source checkouts"],"tags":["cli","link","version-resolution"],"backgroundTag":"invalid-cli-argument","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}