immich-app/immich · warning · HTTPException
Image has zero width or height
Error message
Image has zero width or height
What it means
predict validates the uploaded image before inference. If decode_pil produces an image whose width or height is 0, the endpoint raises HTTP 400 'Image has zero width or height' because downstream models cannot process a degenerate image.
Solutions
- Check the source file is a fully written, non-empty image before sending it to the ML endpoint.
- Re-encode or re-fetch the asset; the original data is corrupt.
- On the client, pre-validate image dimensions before calling predict.
Example fix
# before
requests.post(f"{ml}/predict", files={"image": open(p, 'rb')})
# after
from PIL import Image
img = Image.open(p); img.verify()
with Image.open(p) as im:
if im.width == 0 or im.height == 0:
skip(p)
else:
requests.post(f"{ml}/predict", files={"image": open(p, 'rb')}) Defensive patterns
Strategy: validation
Validate before calling
from PIL import Image
with Image.open(path) as im:
im.verify()
with Image.open(path) as im:
assert im.width > 0 and im.height > 0 Try / catch
try:
r = requests.post(f"{ml}/predict", files={"image": f})
r.raise_for_status()
except requests.HTTPError as e:
if e.response.status_code == 400: skip_asset(asset_id) Prevention
- Verify image integrity client-side before upload.
- Skip zero-byte or still-being-written files.
- Re-fetch/re-encode assets that fail repeatedly.
When it happens
Trigger: Uploading a corrupted/truncated image, an image whose header declares zero dimensions, or an empty/partial byte stream that PIL decodes into a zero-sized image.
Common situations: Thumbnailing a file that was still being written; interrupted uploads; exotic formats PIL partially decodes; test fixtures with empty buffers.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Asset dimensions are not available for editing
- assetIds, albumId, or userId is required
- At least two people are required for merging
- Cannot add another owner
- Cannot merge a person into themselves
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/7ba158ca3dfc78fa.
Report an issue: GitHub.
Appendix: source
Thrown at machine-learning/immich_ml/main.py:175
async def root() -> ORJSONResponse:
return ORJSONResponse({"message": "Immich ML"})
@app.get("/ping")
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]View on GitHub (pinned to e55ac299a4)