roboflow/supervision · error · ValueError

Triggering anchors cannot be empty.

Error message

Triggering anchors cannot be empty.

What it means

LineZone's constructor validates that the triggering_anchors iterable is non-empty; an empty sequence means no keypoint could ever cross the line, so counting would silently produce zeros forever. The library prefers failing fast at construction over a useless-but-quiet tracker.

Source

Thrown at src/supervision/detection/line_zone.py:129

                crossed the line. This is useful when dealing with unstable
                bounding boxes or when detections may linger on the line.
        """
        self.vector = Vector(start=start, end=end)
        self.limits = self._calculate_region_of_interest_limits(vector=self.vector)
        self.crossing_history_length = max(2, minimum_crossing_threshold + 1)
        self.crossing_state_history: dict[int, deque[bool]] = defaultdict(
            lambda: deque(maxlen=self.crossing_history_length)
        )
        # Tracks consecutive frames a tracker key has been absent; eviction
        # requires crossing_history_length absent frames so that ByteTrack
        # coasting gaps (single-frame detection drops) don't reset mid-crossing
        # state prematurely.
        self._tracker_frames_absent: dict[int, int] = {}
        self._in_count_per_class: Counter[int | None] = Counter()
        self._out_count_per_class: Counter[int | None] = Counter()
        self.triggering_anchors = triggering_anchors
        if not list(self.triggering_anchors):
            raise ValueError("Triggering anchors cannot be empty.")
        self.class_id_to_name: dict[int, str] = {}

    @property
    def in_count(self) -> int:
        return sum(self._in_count_per_class.values())

    @property
    def out_count(self) -> int:
        return sum(self._out_count_per_class.values())

    @property
    def in_count_per_class(self) -> dict[int | None, int]:
        return dict(self._in_count_per_class)

    @property
    def out_count_per_class(self) -> dict[int | None, int]:
        return dict(self._out_count_per_class)

View on GitHub (pinned to 7f254d9784)

Solutions

  1. Pass at least one anchor, most commonly sv.Position.CENTER or an index list like [0, 1] for pose keypoints.
  2. If anchors come from a pose config, assert the selection is non-empty before constructing LineZone.
  3. Default to [sv.Position.CENTER] when your detection has no keypoints.

Example fix

# before
 zone = sv.LineZone(start=start, end=end, triggering_anchors=[])

# after
 zone = sv.LineZone(start=start, end=end, triggering_anchors=[sv.Position.CENTER])
Defensive patterns

Strategy: validation

Validate before calling

anchors = [a for a in requested_anchors if a is not None]
if not anchors:
    anchors = [sv.Position.CENTER]
zone = sv.LineZone(start=start, end=end, triggering_anchors=anchors)

Prevention

When it happens

Trigger: Constructing sv.LineZone(start=..., end=..., triggering_anchors=[]) — e.g. passing an empty list literal, an anchors selection computed from a pose model with zero keypoints, or a variable that was filtered down to nothing (like [k for k in range(17) if k in selected] with an empty selected set).

Common situations: Building triggering_anchors dynamically from a per-model keypoint list that is empty for the chosen model; refactoring from hardcoded anchors (e.g. [sv.Position.CENTER]) to computed ones; copy-paste from an example where the anchors list was deleted.

Related errors


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