pypa/pip · error · ValueError

Unknown: %r

Error message

Unknown: %r

What it means

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.

Source

Thrown at src/pip/_vendor/distlib/util.py:1133

    def remove(self, pred, succ):
        assert pred != succ
        try:
            preds = self._preds[succ]
            succs = self._succs[pred]
        except KeyError:  # pragma: no cover
            raise ValueError('%r not a successor of anything' % succ)
        try:
            preds.remove(pred)
            succs.remove(succ)
        except KeyError:  # pragma: no cover
            raise ValueError('%r not a successor of %r' % (succ, pred))

    def is_step(self, step):
        return (step in self._preds or step in self._succs or step in self._nodes)

    def get_steps(self, final):
        if not self.is_step(final):
            raise ValueError('Unknown: %r' % final)
        result = []
        todo = []
        seen = set()
        todo.append(final)
        while todo:
            step = todo.pop(0)
            if step in seen:
                # if a step was already seen,
                # move it to the end (so it will appear earlier
                # when reversed on return) ... but not for the
                # final step, as that would be confusing for
                # users
                if step != final:
                    result.remove(step)
                    result.append(step)
            else:
                seen.add(step)
                result.append(step)

View on GitHub (pinned to f399c37189)

Solutions

  1. Ensure the final node is added with add_node() (or implied via add edges) before calling get_steps.
  2. Guard: if sequencer.is_step(final): before get_steps.
  3. Verify node names against the set of known steps before querying.

Example fix

# before
order = seq.get_steps('build')
# after
if seq.is_step('build'):
    order = seq.get_steps('build')
Defensive patterns

Strategy: validation

Validate before calling

def safe_get_steps(seq, final):
    if seq.is_step(final):
        return seq.get_steps(final)
    return None

Type guard

def is_known_step(seq, node) -> bool:
    return seq.is_step(node)

Try / catch

try:
    order = seq.get_steps(final)
except ValueError as e:
    if 'Unknown' in str(e):
        order = []

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08). Data as JSON: /api/errors/6d8b357f831f50db. Report an issue: GitHub.