{"record":{"id":"96732af045bcc3f2","repo":"jdx/mise","slug":"lockfile-contains-multiple-optionless-resolutions","errorCode":null,"errorMessage":"lockfile contains multiple optionless resolutions for {short}@{specifier}","messagePattern":"lockfile contains multiple optionless resolutions for (.+?)@(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/lockfile.rs","lineNumber":3687,"sourceCode":"\n            if legacy_options_fallback && !request_options.is_empty() {\n                let legacy = tools\n                    .iter()\n                    .filter(|tool| tool.specifiers.contains(specifier) && tool.options.is_empty())\n                    .collect_vec();\n                match legacy.as_slice() {\n                    [] => {}\n                    [found] => {\n                        trace!(\n                            \"[{short}@{specifier}] found {} in lockfile without options, keeping the version pin and dropping its artifact data\",\n                            found.version\n                        );\n                        return Ok(Some(lockfile_tool_with_request_options(\n                            found,\n                            request_options,\n                        )));\n                    }\n                    _ => bail!(\n                        \"lockfile contains multiple optionless resolutions for {short}@{specifier}\"\n                    ),\n                }\n            }\n\n            // Mixed-format monorepo migration can temporarily place legacy\n            // entries without bindings in a version-1 file. Keep those pins\n            // reachable until a successful full format upgrade binds them.\n            let version_matches = |v: &LockfileTool| {\n                v.specifiers.is_empty()\n                    && lockfile_version_matches(prefix, &v.version)\n                    && (!require_prefix_boundary\n                        || lockfile_version_matches_prefix_boundary(prefix, &v.version))\n            };\n            let matching = tools\n                .iter()\n                .filter(|v| version_matches(v) && &v.options == request_options)\n                .collect_vec();","sourceCodeStart":3669,"sourceCodeEnd":3705,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/lockfile.rs#L3669-L3705","documentation":"During resolution lookup with the legacy (optionless) fallback path, mise expects at most one lockfile entry for short@specifier without request options. If multiple optionless entries match, the resolution is ambiguous and mise bails instead of guessing.","triggerScenarios":"Resolving short@specifier against a lockfile where the legacy/optionless matching path finds two or more entries with no options. Caused by duplicated lockfile rows from merges, concurrent lock writes, or hand edits — often seen during mixed-format monorepo migration.","commonSituations":"Git merge duplicated optionless [[tools.x]] entries; an interrupted `mise lock` left multiple rows; migration between lockfile formats temporarily created both legacy and new entries that collide on lookup.","solutions":["Deduplicate the [[tools.<short>]] entries in mise.lock so only one optionless entry exists for that specifier","Regenerate mise.lock from scratch with `mise lock` after backing it up","Complete the monorepo lockfile migration (run `mise lock --upgrade` at the root) so legacy duplicate entries are collapsed"],"exampleFix":"# before (mise.lock)\n[[tools.node]]\nversion = \"20.0.0\"\n[[tools.node]]\nversion = \"20.0.0\"\n# after\n[[tools.node]]\nversion = \"20.0.0\"","handlingStrategy":"validation","validationCode":"// Detect duplicate optionless entries for a tool before lookup\nfn optionless_dupes(entries: &[TomlToolEntry]) -> bool {\n    entries.iter().filter(|e| e.options.is_empty()).count() > 1\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Complete lockfile migrations promptly (`mise lock --upgrade`) so legacy and new entries don't coexist","Regenerate rather than merge lockfiles manually","Avoid parallel mise invocations against the same checkout"],"tags":["lockfile","ambiguity","duplicates","migration"],"backgroundTag":"internal-invariant-violation","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"}