immich-app/immich · error · HTTPException
Either image or text must be provided
Error message
Either image or text must be provided
What it means
Raised as HTTPException(400) by the /predict endpoint when neither an 'image' nor a 'text' form field is present. The endpoint requires at least one of the two as the inference payload.
Source
Thrown at machine-learning/immich_ml/main.py:180
def ping() -> PlainTextResponse:
return PlainTextResponse("pong")
@app.post("/predict", dependencies=[Depends(update_state)])
async def predict(
entries: InferenceEntries = Depends(get_entries),
image: bytes | None = File(default=None),
text: str | None = Form(default=None),
) -> Any:
if image is not None:
decoded = await run(lambda: decode_pil(image))
if decoded.width == 0 or decoded.height == 0:
raise HTTPException(400, "Image has zero width or height")
inputs: Image | str = decoded
elif text is not None:
inputs = text
else:
raise HTTPException(400, "Either image or text must be provided")
response = await run_inference(inputs, entries)
return ORJSONResponse(response)
async def run_inference(payload: Image | str, entries: InferenceEntries) -> InferenceResponse:
outputs: dict[ModelIdentity, Any] = {}
response: InferenceResponse = {}
async def _run_inference(entry: InferenceEntry) -> None:
model = await model_cache.get(
entry["name"], entry["type"], entry["task"], ttl=settings.model_ttl, **entry["options"]
)
inputs = [payload]
for dep in model.depends:
try:
inputs.append(outputs[dep])
except KeyError:
message = f"Task {entry['task']} of type {entry['type']} depends on output of {dep}"View on GitHub (pinned to 199723261c)
Solutions
- Ensure the request includes either a non-null image file or a text form field.
- Inspect the multipart body actually sent (DevTools/curl -v) to confirm the field names 'image' and 'text'.
- If doing CLIP textual search, send text even if empty-looking is not allowed — send an actual non-empty string, or attach an image.
Example fix
# before curl -F 'entries=<json' http://ml/predict # no image/text # after curl -F 'entries=<json' -F 'image=@photo.jpg' http://ml/predict # or curl -F 'entries=<json' -F 'text=a cat' http://ml/predict
Defensive patterns
Strategy: validation
Validate before calling
if image is None and (text is None or text == ''):
raise HTTPException(400, 'Either image or text must be provided') Type guard
def has_payload(image, text) -> bool:
return image is not None or (text is not None and text != '') Try / catch
try:
resp = await run_inference(inputs, entries)
except HTTPException as e:
if e.status_code == 400: client_error()
raise Prevention
- Always attach exactly one of image/text when calling /predict.
- Verify multipart field names with curl -v before integrating.
When it happens
Trigger: POST /predict with both image and text omitted (e.g. only the 'entries' field supplied), or form-encoding bug that drops both fields.
Common situations: Custom client forgets to attach the file/text; a middleware or proxy strips multipart fields; smart-search sends text but it is empty string (note: empty string is still 'not None', so this fires only when the field is truly absent).
Related errors
- Invalid request format.
- Task {entry['task']} of type {entry['type']} depends on outp
- Image has zero width or height
- Failed to load model '{model.model_name}'
- Invalid CLIP dimension size: ${dimSize}
AI-assisted analysis of immich-app/immich@199723261c (2026-08-12).
Data as JSON: /api/errors/4eb0696a27428b84.
Report an issue: GitHub.