{"slug": "fixing-there-are-no-faces-in-the-image-in-rekognition-searchfacesbyimage", "title": "Fixing 'There are no faces in the image' in Rekognition SearchFacesByImage", "summary": "A developer documented the root cause of the `InvalidParameterException: There are no faces in the image` error from Amazon Rekognition's SearchFacesByImage, explaining that the API detects only the single largest face in the input image before searching the collection. The writeup attributes most failures to faces that are small relative to the frame, over-tight client-side crops, extreme head poses, and poor lighting or sharpness, and recommends calling DetectFaces on the same bytes to diagnose, cropping group shots with a margin, and catching the exception to return a friendly retry message instead of a 500.", "body_md": "**Editor note for Ashish (delete before publishing):** this draft was written with AI. Rewrite it in your own voice and check every claim. If any AI-written text remains, add a line saying the post was written with AI assistance (DEV.to and Medium both require this).\n\n**TL;DR** SearchFacesByImage first detects the **largest** face in your input image. If it finds none, it fails with `InvalidParameterException: There are no faces in the image. Should be at least 1.` The usual causes are a face that is small relative to the frame, a selfie cropped too tightly, an extreme head pose, or a dark or blurry photo. Call `DetectFaces` on the same bytes to see which one you hit, crop group shots around the face with a margin, and catch the exception so your user gets \"try another photo\" instead of a 500.\n\nThis is the error every selfie-search feature runs into in its first week of real traffic. Test photos work. Then real users upload a photo of themselves from across the room at a wedding, or a selfie their camera app already cropped to the face, and the call fails before any searching happens.\n\n```\nbotocore.errorfactory.InvalidParameterException: An error occurred (InvalidParameterException)\nwhen calling the SearchFacesByImage operation: There are no faces in the image. Should be at least 1.\n```\n\n`InvalidParameterException` is a generic \"input violated a constraint\" error with HTTP status 400, so the message text is the only thing that tells you it was face detection that failed and not, say, a bad `CollectionId`.\n\nPer the [API reference](https://docs.aws.amazon.com/rekognition/latest/APIReference/API_SearchFacesByImage.html), the operation runs detection first, takes the single largest face it found, and only then searches the collection with it. Two consequences matter:\n\n`IndexFaces` and then `SearchFaces` by face ID.`FaceMatches` list for it.\nThe [quota page](https://docs.aws.amazon.com/rekognition/latest/dg/limits.html) says a face must be at least **40×40 pixels in a 1920×1080 image**, and that larger images need a proportionally larger face. The [input-image recommendations](https://docs.aws.amazon.com/rekognition/latest/dg/recommendations-facial-input-images.html) give 50×50 at the same resolution. Either way, the limit is relative. A face that is 60 pixels tall in a 6000×4000 photo behaves like a face of about 16 pixels in a 1080p frame, far below the minimum.\n\nThis is why downscaling a large photo doesn't help: the face shrinks with it. Cropping does help, because it makes the face a larger share of the frame.\n\nThe opposite mistake. Some upload widgets and camera apps crop to the face before you ever see the image. AWS's recommendation is explicit: the image \"should contain the full head and shoulders of the person. It should not be cropped to the face bounding box.\" If your client code crops, leave a margin of roughly one face-width on every side.\n\nAWS recommends pitch under 30° looking down and under 45° looking up, and yaw under 45° either way. Roll (head tilt) has no restriction, so a sideways phone photo is rarely the cause on its own. Profile shots and people looking down at a phone are.\n\nNight-time event photos with motion blur, heavy backlight, or a face in deep shadow. `IndexFaces` reports these as `UnindexedFaces` with reasons like `LOW_BRIGHTNESS` and `LOW_SHARPNESS`, and `SearchFacesByImage` simply fails to find a face.\n\nSunglasses, masks, a hand over the mouth, or a phone in front of the face during a mirror selfie. AWS asks for both eyes open and visible.\n\n`SearchFacesByImage` defaults `QualityFilter` to `NONE`. If your code sets `LOW`, `MEDIUM` or `HIGH`, a borderline selfie can be filtered out before search. Set it back to `NONE` while debugging to see whether the filter or detection is what rejects the face.\n\n**Info:** Not the same error: `InvalidImageFormatException` means the bytes aren't a PNG or JPEG. Rekognition accepts only those two formats, so iPhone HEIC uploads fail with it, and so does passing a base64 string to `Image={\"Bytes\": ...}` in boto3 (boto3 encodes the bytes for you). `ImageTooLargeException` means raw bytes over 5 MB; S3 objects can be up to 15 MB.\n\n`DetectFaces` with `Attributes=[\"ALL\"]` returns every face it sees with its bounding box, pose and quality scores. Run it on the exact bytes that failed. If it returns nothing, the problem is the image. If it returns a face, the numbers tell you which cause above you hit. Note that `DetectFaces` is a separately billed call, so use it for debugging and sampling, not on every request.\n\n*Run on the bytes that failed. Prints size relative to the 1080p minimum, pose and quality.*\n\n``` python\nimport boto3\nfrom PIL import Image\nimport io\n\nrek = boto3.client(\"rekognition\", region_name=\"us-east-1\")\n\ndef explain(image_bytes: bytes) -> None:\n    w, h = Image.open(io.BytesIO(image_bytes)).size\n    faces = rek.detect_faces(Image={\"Bytes\": image_bytes}, Attributes=[\"ALL\"])[\"FaceDetails\"]\n    if not faces:\n        print(f\"{w}x{h}: no face detected at all\")\n        return\n    for f in faces:\n        box = f[\"BoundingBox\"]\n        face_px = min(box[\"Width\"] * w, box[\"Height\"] * h)\n        # Scale to what this face would measure in a 1920x1080 frame.\n        at_1080p = face_px * 1080 / min(w, h)\n        p, q = f[\"Pose\"], f[\"Quality\"]\n        print(\n            f\"face ~{face_px:.0f}px ({at_1080p:.0f}px at 1080p, min ~40-50) \"\n            f\"yaw={p['Yaw']:.0f} pitch={p['Pitch']:.0f} \"\n            f\"brightness={q['Brightness']:.0f} sharpness={q['Sharpness']:.0f}\"\n        )\n```\n\nThe error is a user-input problem, so treat it like a validation error. Catch it by code and message, and ask for another photo.\n\n``` python\nfrom botocore.exceptions import ClientError\n\ndef search_selfie(collection_id: str, image_bytes: bytes):\n    try:\n        return rek.search_faces_by_image(\n            CollectionId=collection_id,\n            Image={\"Bytes\": image_bytes},\n            FaceMatchThreshold=90,\n            MaxFaces=50,\n        )[\"FaceMatches\"]\n    except ClientError as e:\n        err = e.response[\"Error\"]\n        if err[\"Code\"] == \"InvalidParameterException\" and \"no faces\" in err[\"Message\"].lower():\n            return None  # tell the user: \"We couldn't see a face. Try a closer, well-lit photo.\"\n        raise\n```\n\n`ImageOps.exif_transpose` plus a JPEG re-encode fixes both, and keeps you under the 5 MB bytes limit.\n*Rotation, optional crop with margin, JPEG under the 5 MB bytes limit.*\n\n``` python\nimport io\nfrom PIL import Image, ImageOps\n\ndef prepare(path: str, crop=None, max_side=2048) -> bytes:\n    img = ImageOps.exif_transpose(Image.open(path)).convert(\"RGB\")\n    if crop:  # (left, top, width, height) as ratios, e.g. from a tap or a detector\n        l, t, cw, ch = crop\n        W, H = img.size\n        mx, my = cw * W, ch * H  # one face-width of margin each side\n        img = img.crop((\n            max(0, l * W - mx), max(0, t * H - my),\n            min(W, (l + cw) * W + mx), min(H, (t + ch) * H + my),\n        ))\n    img.thumbnail((max_side, max_side))\n    buf = io.BytesIO()\n    img.save(buf, \"JPEG\", quality=90)\n    return buf.getvalue()\n```\n\nWe build [SightRadar](https://sightradar.com/?utm_source=devto&utm_medium=referral&utm_campaign=launch-2026q4&utm_content=rekognition-searchfacesbyimage-no-faces-in-the-image), a face search API that keeps Rekognition's collection model (create a collection, index photos, search by selfie), so this is a problem we handle every day. Two differences are relevant here:\n\n`200` with an empty `matches` list and a `reason` of `no_face` or `low_quality_selfie`, so the \"ask for another photo\" branch is a field check, not an exception handler. Like any processed photo, the call is billed.\n\n``` python\nimport os, requests\n\nr = requests.post(\n    f\"https://api.sightradar.com/v1/collections/{collection_id}/search\",\n    headers={\"Authorization\": f\"Bearer {os.environ['SIGHTRADAR_API_KEY']}\"},\n    files={\"file\": open(\"selfie.jpg\", \"rb\")},\n    data={\"limit\": \"50\"},\n    timeout=30,\n)\nbody = r.json()\nif not body[\"matches\"] and body.get(\"reason\") in (\"no_face\", \"low_quality_selfie\"):\n    print(\"Ask for another photo:\", body[\"reason\"])\nfor m in body[\"matches\"]:\n    print(m[\"photo_id\"], round(m[\"score\"], 3))\n```\n\nIf you already have boto3 code, the [Rekognition shim](https://sightradar.com/docs/sdks/rekognition-shim?utm_source=devto&utm_medium=referral&utm_campaign=launch-2026q4&utm_content=rekognition-searchfacesbyimage-no-faces-in-the-image) keeps your `search_faces_by_image` calls and converts the 0 to 100 threshold scale. The [migration guide](https://sightradar.com/blog/migrate-indexfaces-searchfacesbyimage-from-aws-rekognition?utm_source=devto&utm_medium=referral&utm_campaign=launch-2026q4&utm_content=rekognition-searchfacesbyimage-no-faces-in-the-image) covers re-indexing and cut-over.\n\nTry detection on your own problem photos. New accounts get free credits, no card. [Open the face detector](https://sightradar.com/tools/face-detector?utm_source=devto&utm_medium=referral&utm_campaign=launch-2026q4&utm_content=rekognition-searchfacesbyimage-no-faces-in-the-image)\n\nRekognition's minimum face size is relative to the image: about 40 to 50 pixels in a 1920x1080 frame, scaled up for larger images. A face that looks fine to you in a 24-megapixel group photo can be far below that. Tight crops, extreme head pose, darkness, blur and occlusion are the other common causes.\n\nDownscaling does not, because the face shrinks in proportion. Cropping around the face does, because the face becomes a larger share of the frame. Keep a margin so the crop still shows head and shoulders.\n\nSearchFacesByImage only searches the largest face. To search every face, call IndexFaces on the photo, then call SearchFaces with each returned FaceId.\n\nInvalidParameterException with the message 'There are no faces in the image' means the image decoded but no face was detected. InvalidImageFormatException means the bytes are not a PNG or JPEG, for example an iPhone HEIC file or a base64 string passed where raw bytes are expected.\n\n*The face search API used in the examples. Originally published on the [SightRadar blog](https://sightradar.com/blog/rekognition-searchfacesbyimage-no-faces-in-the-image).*", "url": "https://wpnews.pro/news/fixing-there-are-no-faces-in-the-image-in-rekognition-searchfacesbyimage", "canonical_source": "https://dev.to/ashishsikka/fixing-there-are-no-faces-in-the-image-in-rekognition-searchfacesbyimage-5d1n", "published_at": "2026-10-31 03:10:21+00:00", "updated_at": "2026-10-31 03:19:28.502625+00:00", "lang": "en", "topics": ["computer-vision", "ai-tools", "developer-tools"], "entities": ["Amazon Rekognition", "AWS", "SearchFacesByImage", "DetectFaces", "IndexFaces"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/fixing-there-are-no-faces-in-the-image-in-rekognition-searchfacesbyimage", "markdown": "https://wpnews.pro/news/fixing-there-are-no-faces-in-the-image-in-rekognition-searchfacesbyimage.md", "text": "https://wpnews.pro/news/fixing-there-are-no-faces-in-the-image-in-rekognition-searchfacesbyimage.txt", "jsonld": "https://wpnews.pro/news/fixing-there-are-no-faces-in-the-image-in-rekognition-searchfacesbyimage.jsonld"}}