roboflow/supervision · error · ValueError

Number of colors ({len(colors)}) must match number of key po

Error message

Number of colors ({len(colors)}) must match number of key points ({points_count}).

What it means

Raised by verify_clean_wheel.py's _wheel_metadata when opening a wheel archive does not yield exactly one path ending in '/METADATA'. A valid wheel contains precisely one *.dist-info/METADATA file; zero means the wheel is malformed or the file is misplaced/misnamed, and more than one means duplicate dist-info directories got packed in. The script refuses to guess which metadata to validate.

Source

Thrown at src/supervision/key_points/annotators.py:989

        else:
            resolved = labels

        if len(resolved) != points_count:
            raise ValueError(
                f"Number of labels ({len(resolved)}) must match "
                f"number of key points ({points_count})."
            )
        return resolved

    @staticmethod
    def _resolve_color_list(
        colors: Color | list[Color],
        points_count: int,
    ) -> list[Color]:
        """Return a per-keypoint color list for a single instance."""
        if isinstance(colors, list):
            if len(colors) != points_count:
                raise ValueError(
                    f"Number of colors ({len(colors)}) must match "
                    f"number of key points ({points_count})."
                )
            return colors
        return [colors] * points_count

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Inspect the archive: unzip -l yourwheel.whl | grep METADATA and confirm there is exactly one <name>.dist-info/METADATA entry.
  2. If zero entries: rebuild the wheel with a standard backend (python -m build --wheel) from a clean checkout instead of custom zipping.
  3. If multiple entries: delete stale dist-info directories from the build dir and rebuild; never merge two wheels' contents.
  4. Verify you are passing an actual built wheel (fresh artifact), not a renamed zip or sdist, to verify_clean_wheel.py.

Example fix

# before: hand-zipped 'wheel' with misplaced metadata
zip -r custom.whl mypackage/ METADATA  # METADATA at archive root -> 0 matches

# after: build a compliant wheel
# python -m build --wheel
# dist/supervision-*.whl now contains supervision-x.y.z.dist-info/METADATA
Defensive patterns

Strategy: validation

Validate before calling

import zipfile, pathlib

def is_clean_wheel(wheel: pathlib.Path) -> bool:
    """True if the archive has exactly one */METADATA entry (valid wheel layout)."""
    if not wheel.name.endswith('.whl'):
        return False
    with zipfile.ZipFile(wheel) as z:
        return len([n for n in z.namelist() if n.endswith('/METADATA')]) == 1

Prevention

When it happens

Trigger: Passing a path that is not a real wheel (a zip renamed .whl, or an sdist); a custom build step that writes METADATA at a non-standard path (no '<pkg>.dist-info/' prefix, so endswith('/METADATA') misses it); a packaging bug or manual re-zip producing two dist-info directories; a corrupted download producing a truncated archive read as having no metadata.

Common situations: CI downloading wheels from an artifact store that mangles names or contents; developers hand-editing/re-zipping wheels to patch metadata; broken custom build backends (setuptools plugin, bazel rules) emitting non-compliant wheel layouts; pointing the verifier at the dist/ directory glob that matches a stale wheel plus a new one and reading the wrong file.

Related errors


AI-assisted analysis of roboflow/supervision@7f254d9784 (2026-08-15). Data as JSON: /api/errors/6f76c3a4c038e2b3. Report an issue: GitHub.