ageitgey/face_recognition · error · ValueError
Invalid landmarks model type. Supported models are ['small',
Error message
Invalid landmarks model type. Supported models are ['small', 'large'].
What it means
This ValueError is raised by face_recognition.face_landmarks() (face_recognition/api.py:200) when the model argument is neither 'large' nor 'small'. The function only maps raw dlib landmark parts into named features for those two exact strings, so any other value falls through the if/elif chain into the else branch. It exists to prevent silently returning unmapped or wrongly-mapped landmark indices for an unrecognized predictor model.
Source
Thrown at face_recognition/api.py:200
return [{
"chin": points[0:17],
"left_eyebrow": points[17:22],
"right_eyebrow": points[22:27],
"nose_bridge": points[27:31],
"nose_tip": points[31:36],
"left_eye": points[36:42],
"right_eye": points[42:48],
"top_lip": points[48:55] + [points[64]] + [points[63]] + [points[62]] + [points[61]] + [points[60]],
"bottom_lip": points[54:60] + [points[48]] + [points[60]] + [points[67]] + [points[66]] + [points[65]] + [points[64]]
} for points in landmarks_as_tuples]
elif model == 'small':
return [{
"nose_tip": [points[4]],
"left_eye": points[2:4],
"right_eye": points[0:2],
} for points in landmarks_as_tuples]
else:
raise ValueError("Invalid landmarks model type. Supported models are ['small', 'large'].")
def face_encodings(face_image, known_face_locations=None, num_jitters=1, model="small"):
"""
Given an image, return the 128-dimension face encoding for each face in the image.
:param face_image: The image that contains one or more faces
:param known_face_locations: Optional - the bounding boxes of each face if you already know them.
:param num_jitters: How many times to re-sample the face when calculating encoding. Higher is more accurate, but slower (i.e. 100 is 100x slower)
:param model: Optional - which model to use. "large" or "small" (default) which only returns 5 points but is faster.
:return: A list of 128-dimensional face encodings (one for each face in the image)
"""
raw_landmarks = _raw_face_landmarks(face_image, known_face_locations, model)
return [np.array(face_encoder.compute_face_descriptor(face_image, raw_landmark_set, num_jitters)) for raw_landmark_set in raw_landmarks]
def compare_faces(known_face_encodings, face_encoding_to_check, tolerance=0.6):
"""View on GitHub (pinned to 9f3061aaee)
Solutions
- Set model to one of the two supported exact strings: face_landmarks(image, model='large') for the full 68-point layout (chin, eyebrows, eyes, nose, lips) or model='small' for the fast 5-point layout (eyes + nose tip).
- If the value comes from user input, config, or a CLI flag, validate it against {'small','large'} before calling and fail early with your own error message.
- Check for typos and casing — the comparison is case-sensitive exact match, so 'Large', 'SMALL', or 'large ' (trailing space) all raise; strip and .lower() inbound strings.
- If you intended a detection model ('cnn'/'hog'), that belongs to face_locations(...), not face_landmarks; move the argument to the right function.
- Omit the argument entirely to accept the documented default model='large'.
Example fix
// before landmarks = face_recognition.face_landmarks(img, model="cnn") # ValueError // after face_locations = face_recognition.face_locations(img, model="cnn") landmarks = face_recognition.face_landmarks(img, face_locations, model="large")
Defensive patterns
Strategy: validation
Validate before calling
ALLOWED_LANDMARK_MODELS = {"small", "large"}
def get_landmark_model(candidate):
candidate = (candidate or "large").strip().lower()
if candidate not in ALLOWED_LANDMARK_MODELS:
raise ValueError(
f"Unknown landmarks model {candidate!r}; "
f"expected one of {sorted(ALLOWED_LANDMARK_MODELS)}"
)
return candidate
model = get_landmark_model(config.get("landmark_model"))
landmarks = face_recognition.face_landmarks(image, model=model) Type guard
def is_valid_landmarks_model(model) -> bool:
return isinstance(model, str) and model in {"small", "large"}
assert is_valid_landmarks_model(model), f"bad model: {model!r}" Try / catch
try:
landmarks = face_recognition.face_landmarks(image, model=model)
except ValueError as e:
if "landmarks model type" in str(e):
# bad model name: correct it and retry once with the safe default
landmarks = face_recognition.face_landmarks(image, model="large")
else:
raise Prevention
- Whitelist model against {'small','large'} at the config/CLI boundary instead of passing raw strings into the library.
- Normalize inbound values with .strip().lower() before use; matching inside the library is exact and case-sensitive.
- Keep detection models ('cnn','hog') and landmark/encoding models ('large','small') in separate config fields so they cannot be swapped by mistake.
- Pin the face_recognition version in requirements so accepted model names cannot drift under you.
When it happens
Trigger: Calling face_landmarks(image, model=...) with a string other than 'large' or 'small' — e.g. model='medium', model='68', model='5', or a differently-cased value like 'Large'. It also triggers on typos and on values intended for a different API (face_encodings accepts 'large'/'small' too, but models like 'cnn' or 'hog' belong to face_locations and will fail here).
Common situations: Copying a model name from face_locations(model='cnn') into face_landmarks; passing a CLI/config value that is not whitelisted before reaching the library; assuming the landmark-count (68/5) is the model name; locale/case mismatch such as 'LARGE'; upgrading code that hardcodes a model string that was renamed or never existed for this function.
AI-assisted analysis of ageitgey/face_recognition@9f3061aaee (2026-08-15).
Data as JSON: /api/errors/a622724296cb6fdc.
Report an issue: GitHub.