roboflow/supervision · error · ValueError

No labels defined for class_id={class_id}.

Error message

No labels defined for class_id={class_id}.

What it means

Raised by verify_clean_wheel.py's _validate_manifest when the set of non-comment, non-empty lines in the fallback smoke-manifest file does not exactly equal the script's hardcoded _MANIFEST_CHECKS set ({'draw-box', 'draw-rectangle', 'required-pyav', ...}). The manifest lists the smoke checks run against the installed wheel; the script requires the file and the expected contract to stay in lockstep so the fallback verification cannot silently lose coverage.

Source

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

    @staticmethod
    def _resolve_labels(
        labels: list[str] | dict[int, list[str]] | None,
        points_count: int,
        class_id: int | None = None,
    ) -> list[str]:
        """Return the label list for a single instance."""
        if labels is None:
            return [str(j) for j in range(points_count)]

        resolved: list[str]
        if isinstance(labels, dict):
            if class_id is None:
                raise ValueError(
                    "labels is a dict but class_id is None; "
                    "KeyPoints must have class_id set."
                )
            if class_id not in labels:
                raise ValueError(f"No labels defined for class_id={class_id}.")
            resolved = labels[class_id]
        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):

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Read the error message: it prints both the found set and the expected set — diff them to see the exact added/missing entry.
  2. If you intentionally changed the manifest, update _MANIFEST_CHECKS in .github/scripts/verify_clean_wheel.py to match (or reverse the change).
  3. Check for accidental lines: comments must start with '#'; blank lines are ignored but anything else counts as a check name.
  4. Re-run the script to confirm the sets now match exactly.

Example fix

# before: manifest adds a new check but script constant is stale
# manifest file:  draw-box\ndraw-rectangle\nrequired-pyav\ndraw-label   <- new line

# after: update the paired constant in verify_clean_wheel.py
_MANIFEST_CHECKS = {
    "draw-box",
    "draw-rectangle",
    "required-pyav",
    "draw-label",
}
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

def manifest_matches_expected(manifest: Path, expected: set[str]) -> bool:
    """Mirror of the script's check: non-comment, non-blank lines vs expected set."""
    checks = {
        s for line in manifest.read_text(encoding='utf-8').splitlines()
        if (s := line.strip()) and not s.startswith('#')
    }
    return checks == expected

Prevention

When it happens

Trigger: Adding, renaming, or deleting a check in the manifest file without updating _MANIFEST_CHECKS in verify_clean_wheel.py (or vice versa); trailing whitespace or a stray non-comment line in the manifest being picked up as a check; editing one side on a branch and forgetting the other.

Common situations: Contributors extending the wheel smoke tests; a manifest path change; line-ending or encoding edits introducing phantom entries; rebase/merge where only one side of the paired constant/file was taken.

Related errors


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