deepinsight/insightface · warning · ValueError

multiple faces detected ({face_count}); expected exactly one

Error message

multiple faces detected ({face_count}); expected exactly one face

What it means

Under the MULTI_FACE_REQUIRE_ONE policy, _select_face_from_faces raises ValueError('multiple faces detected (N); expected exactly one face') whenever the detector returns more than one face. The strict policy refuses to pick among candidates, so strict 1:1 evaluation aborts on any multi-identity image (or spurious extra detection).

Source

Thrown at python-package/insightface/gui/core/evaluation.py:168

        offsets = np.vstack(
            [
                (det[:, 0] + det[:, 2]) / 2.0 - img_center[1],
                (det[:, 1] + det[:, 3]) / 2.0 - img_center[0],
            ]
        )
        offset_dist_squared = np.sum(np.power(offsets, 2.0), axis=0)
        return faces[int(np.argmax(bounding_box_size - offset_dist_squared * 2.0))]
    except Exception:
        return max(faces, key=_face_area)


def _select_face_from_faces(faces, image_shape, path: Path, policy: str, stage: str):
    del path, stage
    face_count = len(faces)
    if face_count == 0:
        raise ValueError("no face detected")
    if face_count > 1 and policy == MULTI_FACE_REQUIRE_ONE:
        raise ValueError(f"multiple faces detected ({face_count}); expected exactly one face")
    if face_count > 1 and policy == MULTI_FACE_SKIP:
        raise ValueError(f"skipped multi-face image ({face_count} faces)")
    if face_count > 1 and policy == MULTI_FACE_USE_CENTERED_LARGEST:
        return _largest_centered_face(faces, image_shape)
    if face_count > 1:
        return max(faces, key=_face_area)
    return faces[0]


def select_face_by_policy(faces, image_shape, policy: str = MULTI_FACE_REQUIRE_ONE, path: str | Path = "", stage: str = ""):
    return _select_face_from_faces(
        faces,
        image_shape,
        Path(path) if path else Path("image"),
        _normalize_multi_face_policy(policy),
        stage,
    )

View on GitHub (pinned to 7fadd420c2)

Solutions

  1. Switch policy to MULTI_FACE_USE_CENTERED_LARGEST (deterministic largest centered face) or MULTI_FACE_SKIP for such datasets.
  2. Raise det_thresh to suppress low-confidence spurious detections.
  3. Curate the dataset: remove or crop multi-identity images before strict evaluation.
  4. Catch this ValueError per-image when require_one is mandated and report skips instead of aborting the run.

Example fix

# before
face = select_face_by_policy(faces, img.shape, policy=MULTI_FACE_REQUIRE_ONE)  # ValueError: multiple faces detected (3)

# after
try:
    face = select_face_by_policy(faces, img.shape, policy=MULTI_FACE_REQUIRE_ONE)
except ValueError as e:
    if 'multiple faces detected' in str(e):
        face = select_face_by_policy(faces, img.shape, policy=MULTI_FACE_USE_CENTERED_LARGEST)
    else:
        raise
Defensive patterns

Strategy: fallback

Validate before calling

faces = app.get(img)
if len(faces) > 1 and policy == MULTI_FACE_REQUIRE_ONE:
    policy = MULTI_FACE_USE_CENTERED_LARGEST  # or skip this image

Type guard

def is_single_face_image(faces) -> bool:
    return len(faces) == 1

Try / catch

try:
    face = select_face_by_policy(faces, shape, policy=MULTI_FACE_REQUIRE_ONE)
except ValueError as e:
    if 'multiple faces detected' in str(e):
        face = select_face_by_policy(faces, shape, policy=MULTI_FACE_USE_CENTERED_LARGEST)
    else:
        raise

Prevention

When it happens

Trigger: Calling select_face_by_policy / _embedding_for_image with policy=MULTI_FACE_REQUIRE_ONE on an image where len(faces) > 1 — group photos, posters, background bystanders, or false-positive boxes.

Common situations: Strict verification datasets polluted with group photos; det_thresh too low producing spurious boxes (hands, hair, wall patterns); casual selfie datasets with photobombers.

Related errors


AI-assisted analysis of deepinsight/insightface@7fadd420c2 (2026-08-28). Data as JSON: /api/errors/576f6b2f6290ffef. Report an issue: GitHub.