{"record":{"id":"6d8b357f831f50db","repo":"pypa/pip","slug":"unknown-r","errorCode":null,"errorMessage":"Unknown: %r","messagePattern":"Unknown: %r","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/distlib/util.py","lineNumber":1133,"sourceCode":"    def remove(self, pred, succ):\n        assert pred != succ\n        try:\n            preds = self._preds[succ]\n            succs = self._succs[pred]\n        except KeyError:  # pragma: no cover\n            raise ValueError('%r not a successor of anything' % succ)\n        try:\n            preds.remove(pred)\n            succs.remove(succ)\n        except KeyError:  # pragma: no cover\n            raise ValueError('%r not a successor of %r' % (succ, pred))\n\n    def is_step(self, step):\n        return (step in self._preds or step in self._succs or step in self._nodes)\n\n    def get_steps(self, final):\n        if not self.is_step(final):\n            raise ValueError('Unknown: %r' % final)\n        result = []\n        todo = []\n        seen = set()\n        todo.append(final)\n        while todo:\n            step = todo.pop(0)\n            if step in seen:\n                # if a step was already seen,\n                # move it to the end (so it will appear earlier\n                # when reversed on return) ... but not for the\n                # final step, as that would be confusing for\n                # users\n                if step != final:\n                    result.remove(step)\n                    result.append(step)\n            else:\n                seen.add(step)\n                result.append(step)","sourceCodeStart":1115,"sourceCodeEnd":1151,"githubUrl":"https://github.com/pypa/pip/blob/f399c3718970b1b0e2478dac5296eb62679a9b86/src/pip/_vendor/distlib/util.py#L1115-L1151","documentation":"Raised as ValueError by Sequencer.get_steps when the requested final node is not known to the sequencer — it is not in _preds, _succs, or _nodes (is_step() returns False). get_steps performs a topological walk backward from the final node, so an unknown final makes the walk impossible. This is the public-facing guard against asking for an ordering anchored on a node that was never added.","triggerScenarios":"Calling Sequencer().get_steps('final') without add_node('final'); get_steps on a node removed via remove_node before the ordering query; typo in the final node name.","commonSituations":"Querying an ordering before the graph is fully built; using a target node name from config that doesn't match any added node; post-cleanup queries referencing removed nodes.","solutions":["Ensure the final node is added with add_node() (or implied via add edges) before calling get_steps.","Guard: if sequencer.is_step(final): before get_steps.","Verify node names against the set of known steps before querying."],"exampleFix":"# before\norder = seq.get_steps('build')\n# after\nif seq.is_step('build'):\n    order = seq.get_steps('build')","handlingStrategy":"validation","validationCode":"def safe_get_steps(seq, final):\n    if seq.is_step(final):\n        return seq.get_steps(final)\n    return None","typeGuard":"def is_known_step(seq, node) -> bool:\n    return seq.is_step(node)","tryCatchPattern":"try:\n    order = seq.get_steps(final)\nexcept ValueError as e:\n    if 'Unknown' in str(e):\n        order = []","preventionTips":["Call is_step(final) before get_steps.","Ensure all nodes are added via add_node/add before querying."],"tags":["sequencer","graph","distlib","dependency-ordering","topological-sort"],"backgroundTag":null,"analyzedSha":"f399c3718970b1b0e2478dac5296eb62679a9b86","analyzedAt":"2026-08-08T23:01:42.227Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}