{"record":{"id":"53c8e046794993d6","repo":"roboflow/supervision","slug":"field-attribute-should-be-consistently-none-or","errorCode":null,"errorMessage":"Field '{attribute}' should be consistently None or not None in both Detections.","messagePattern":"Field '(.+?)' should be consistently None or not None in both Detections\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/supervision/detection/core.py","lineNumber":3531,"sourceCode":"def _validate_fields_both_defined_or_none(\n    detections_1: Detections, detections_2: Detections\n) -> None:\n    \"\"\"\n    Verify that for each optional field in the Detections, both instances either have\n    the field set to None or both have it set to non-None values.\n\n    `data` field is ignored.\n\n    Raises:\n        ValueError: If one field is None and the other is not, for any of the fields.\n    \"\"\"\n    attributes = get_instance_variables(detections_1)\n    for attribute in attributes:\n        value_1 = getattr(detections_1, attribute)\n        value_2 = getattr(detections_2, attribute)\n\n        if (value_1 is None) != (value_2 is None):\n            raise ValueError(\n                f\"Field '{attribute}' should be consistently None or not None in both \"\n                \"Detections.\"\n            )\n\n\n@deprecated(  # type: ignore[untyped-decorator]\n    target=_validate_fields_both_defined_or_none,\n    deprecated_in=\"0.29.0\",\n    remove_in=\"0.32.0\",\n)\ndef validate_fields_both_defined_or_none(\n    detections_1: Detections, detections_2: Detections\n) -> None:\n    void(detections_1, detections_2)\n","sourceCodeStart":3513,"sourceCodeEnd":3546,"githubUrl":"https://github.com/roboflow/supervision/blob/7f254d9784d4c37e0f03cd89ddee164c8db099c0/src/supervision/detection/core.py#L3513-L3546","documentation":"_validate_fields_both_defined_or_none checks every instance attribute of two Detections (via get_instance_variables) and requires each field to be None in both or set in both. Merging operations (merge_object_detection_pair etc.) can only combine like-shaped inputs, so any mismatch — e.g. one has tracker_id and the other doesn't — raises this ValueError naming the offending attribute.","triggerScenarios":"Calling merge_object_detection_pair(d1, d2) (or group/merge flows that call this validator) where d1.confidence is set but d2.confidence is None, one has mask and the other doesn't, one has tracker_id and the other doesn't, etc. The 'data' field is ignored.","commonSituations":"Merging detections from two different model types (detector with confidence vs. VLM without); merging tracked and untracked Detections; one side passed through Detections.empty() or a filter that dropped fields; mixing from_inference output with hand-built Detections.","solutions":["Align fields before merging: either strip the extra field (d.tracker_id = None) or populate the missing one (uniform confidence = np.ones(len(d)), zeros class_id).","When one side is empty, use Detections.empty() from the same code path or explicitly None out mismatched fields on both.","Check the named attribute in the message — it tells you exactly which field mismatched."],"exampleFix":"# before\nmerged = merge_object_detection_pair(detect_det, vlm_det)\n# detect_det.confidence is array, vlm_det.confidence is None -> ValueError\n\n# after\nif vlm_det.confidence is None and detect_det.confidence is not None:\n    vlm_det.confidence = np.ones(len(vlm_det), dtype=float)\nmerged = merge_object_detection_pair(detect_det, vlm_det)","handlingStrategy":"validation","validationCode":"def align_detection_fields(d1: sv.Detections, d2: sv.Detections):\n    for name in ('confidence', 'class_id', 'tracker_id', 'mask'):\n        v1, v2 = getattr(d1, name, None), getattr(d2, name, None)\n        if (v1 is None) != (v2 is None):\n            if v1 is None:\n                setattr(d1, name, np.ones(len(d1)) if name == 'confidence' else None)\n                # populate or strip per your policy\n    return d1, d2\n\nd1, d2 = align_detection_fields(d1, d2)\nmerged = merge_object_detection_pair(d1, d2)","typeGuard":"def fields_compatible(d1: sv.Detections, d2: sv.Detections) -> bool:\n    for name in ('confidence', 'class_id', 'tracker_id', 'mask'):\n        if (getattr(d1, name, None) is None) != (getattr(d2, name, None) is None):\n            return False\n    return True","tryCatchPattern":"try:\n    merged = merge_object_detection_pair(d1, d2)\nexcept ValueError as e:\n    if 'consistently None' in str(e):\n        field = str(e).split(\"'\")[1]\n        setattr(d2, field, getattr(d1, field))  # or None-out both\n        merged = merge_object_detection_pair(d1, d2)\n    else:\n        raise","preventionTips":["Only merge Detections from the same pipeline stage","Match field presence before merging (the message names the field)","Uniform confidence np.ones() is a safe filler when the other side has scores"],"tags":["merge","field-mismatch","detections","validation"],"backgroundTag":null,"analyzedSha":"7f254d9784d4c37e0f03cd89ddee164c8db099c0","analyzedAt":"2026-08-15T05:13:01.950Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}