{"record":{"id":"83fdf132a2ff1509","repo":"roboflow/supervision","slug":"either-absolute-distance-or-relative-distance-must","errorCode":null,"errorMessage":"Either absolute_distance or relative_distance must be set.","messagePattern":"Either absolute_distance or relative_distance must be set\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/detection/utils/masks.py","lineNumber":483,"sourceCode":"    if num_labels <= 1:\n        return cast(npt.NDArray[np.bool_], mask.copy())\n\n    areas = stats[1:, cv2.CC_STAT_AREA]\n    max_area = int(areas.max())\n    candidates = 1 + np.flatnonzero(areas == max_area)\n    # Use coordinates for equal-area ties so native and fallback labels agree.\n    main_label = min(\n        (int(label) for label in candidates),\n        key=lambda label: (int(stats[label, 0]), int(stats[label, 1]), label),\n    )\n\n    if relative_distance is not None:\n        diagonal = float(np.hypot(height, width))\n        threshold = float(relative_distance) * diagonal\n    elif absolute_distance is not None:\n        threshold = float(absolute_distance)\n    else:\n        raise ValueError(\"Either absolute_distance or relative_distance must be set.\")\n\n    keep_labels: npt.NDArray[np.bool_] = np.zeros(num_labels, dtype=bool)\n    keep_labels[main_label] = True\n\n    if mode == \"centroid\":\n        differences = centroids[1:] - centroids[main_label]\n        distances = np.sqrt(np.sum(differences**2, axis=1))\n        nearby = 1 + np.where(distances <= threshold)[0]\n        keep_labels[nearby] = True\n    elif mode == \"edge\":\n        main_mask = labels == main_label\n        if np.isnan(threshold) or threshold < 0:\n            nearby_main = np.zeros_like(main_mask)\n        elif np.isposinf(threshold):\n            nearby_main = np.ones_like(main_mask)\n        else:\n            fixed_distances = _chamfer_distances(main_mask)\n            distances = fixed_distances.astype(np.float32) / 65536","sourceCodeStart":465,"sourceCodeEnd":501,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/detection/utils/masks.py#L465-L501","documentation":"The keep-nearby-mask-components style helper needs a distance threshold to decide which connected components are 'near' the main one; the threshold comes either from relative_distance (fraction of the mask diagonal) or absolute_distance (pixels). If both are None there is no way to compute a threshold, so a ValueError is raised.","triggerScenarios":"Calling the function with neither keyword argument, or passing relative_distance=None explicitly intending a default; both branches are checked and the else clause fires.","commonSituations":"Copy-pasting a call and deleting the 'unused' distance argument; wrapping the function and forwarding **kwargs where the distance key was never set; assuming absolute_distance defaults to something sane.","solutions":["Pass relative_distance (e.g. 0.2 = 20% of the diagonal) for resolution-independent behavior.","Or pass absolute_distance in pixels when you know the expected component spacing.","If wrapping the API, set your own default for one of the two parameters."],"exampleFix":"# before\n filtered = filter_non_zero_mask_areas(mask=mask)  # no distance arg\n\n# after\n filtered = filter_non_zero_mask_areas(\n     mask=mask, relative_distance=0.2\n )","handlingStrategy":"validation","validationCode":"if relative_distance is None and absolute_distance is None:\n    relative_distance = 0.2  # app default: 20% of mask diagonal\nresult = filter_non_zero_mask_areas(\n    mask=mask, relative_distance=relative_distance, absolute_distance=absolute_distance\n)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pass one of the two distance arguments.","Prefer relative_distance for resolution-independent pipelines.","Set an explicit default in your wrapper instead of relying on the library to have one."],"tags":["masks","required-argument","validation"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}