{"record":{"id":"33755fa3b16edb58","repo":"jdx/mise","slug":"uv-graph-root-requirements-do-not-match-the-requested","errorCode":null,"errorMessage":"uv graph root requirements do not match the requested package and extras","messagePattern":"uv graph root requirements do not match the requested package and extras","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/backend/pipx/lock.rs","lineNumber":387,"sourceCode":"                let root_requirement = requirements.iter().find(|requirement| {\n                    requirement.get(\"name\").and_then(toml::Value::as_str)\n                        == Some(root_name.as_str())\n                        && requirement.get(\"specifier\").and_then(toml::Value::as_str)\n                            == Some(root_specifier.as_str())\n                });\n                let locked_extras = root_requirement\n                    .and_then(|requirement| requirement.get(\"extras\"))\n                    .and_then(toml::Value::as_array)\n                    .into_iter()\n                    .flatten()\n                    .filter_map(toml::Value::as_str)\n                    .map(|extra| Self::normalize_package_name(extra.trim()))\n                    .collect::<std::collections::BTreeSet<_>>();\n                if requirements.len() != expected.len()\n                    || root_requirement.is_none()\n                    || extras != locked_extras\n                {\n                    bail!(\n                        \"uv graph root requirements do not match the requested package and extras\"\n                    );\n                }\n                virtual_root = true;\n                continue;\n            }\n            if source.len() != 1 || !source.contains_key(\"registry\") {\n                bail!(\"Python locks support registry wheels only\");\n            }\n            if name == Self::normalize_package_name(&self.tool_name())\n                && package.get(\"version\").and_then(toml::Value::as_str) == Some(&tv.version)\n            {\n                root = true;\n            }\n            let wheels = package\n                .get(\"wheels\")\n                .and_then(toml::Value::as_array)\n                .filter(|v| !v.is_empty())","sourceCodeStart":369,"sourceCodeEnd":405,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/backend/pipx/lock.rs#L369-L405","documentation":"The uv lock's graph root must encode exactly the requested package and extras. validate_uv_lock compares the root requirements (normalized package names) and their extras against the request; a count mismatch, a missing root requirement, or differing extras means the lock cannot be trusted for this install and is rejected.","triggerScenarios":"Thrown from validate_uv_lock when the graph's virtual-root requirement set size differs from the expected set, the root requirement entry is absent, or the locked extras (normalized, compared as a BTreeSet) differ from the extras requested in the tool options.","commonSituations":"Adding or removing `[extras]` in the tool options without re-locking; a lock generated for `package[extra1]` replayed for bare `package`; a corrupted or partially hand-edited mise.lock; lock bumped for a different variant of the same tool.","solutions":["Re-lock for the current request: `mise lock --bump <tool>`.","If extras changed unintentionally, restore the original extras option in mise.toml.","Verify the mise.lock root requirement line matches `package[extras]==version` and remove corruption.","Delete the stale lock entry and run `mise lock` to regenerate from scratch."],"exampleFix":"// before: extras added after lock creation\nruff = { version = \"pipx:0.9\", extras = \"all\" }  # lock has no extras\n\n// after: regenerate the lock including extras\n$ mise lock --bump ruff","handlingStrategy":"validation","validationCode":"// confirm locked root matches request before install\nconst lock = parseLock('mise.lock');\nif (lock.rootExtras.join(',') !== requestedExtras.join(',')) run('mise lock --bump <tool>');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Change extras and lock atomically — never bump one without the other","Diff mise.lock root requirement after any tool option change","Let `mise lock` regenerate rather than editing extras in the lock"],"tags":["python","uv","lockfile","extras-mismatch"],"backgroundTag":"schema-validation-failed","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"}