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
- Switch policy to MULTI_FACE_USE_CENTERED_LARGEST (deterministic largest centered face) or MULTI_FACE_SKIP for such datasets.
- Raise det_thresh to suppress low-confidence spurious detections.
- Curate the dataset: remove or crop multi-identity images before strict evaluation.
- 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
- Choose permissive policies for in-the-wild datasets.
- Raise det_thresh to cut spurious detections.
- Pre-crop multi-identity images for strict 1:1 benchmarks.
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
- skipped multi-face image ({face_count} faces)
- no face detected
- no face or embedding
- failed detection
- Identity folder root not found: {root}
AI-assisted analysis of deepinsight/insightface@7fadd420c2 (2026-08-28).
Data as JSON: /api/errors/576f6b2f6290ffef.
Report an issue: GitHub.