odysseus-dev/odysseus · error · HTTPException
Invalid input image: {e}
Error message
Invalid input image: {e} What it means
Raised by _write_bridge_input_image in scripts/mlx_image_server.py when PIL fails to open, convert to RGBA, or PNG-save the uploaded edit image (any exception inside the try block is chained into HTTP 400). It signals malformed or unsupported image bytes rather than a server fault.
Source
Thrown at scripts/mlx_image_server.py:183
if snap.is_file():
return snap
candidates = sorted(snap.rglob("*.safetensors"))
if not candidates:
raise HTTPException(500, f"No safetensors weights found for {model} in {snap}")
return candidates[0]
def _write_bridge_input_image(raw: bytes, out_path: Path) -> None:
try:
from PIL import Image
import io
except Exception as e:
raise HTTPException(503, "Pillow is required for MLX image edit bridge inputs.") from e
try:
img = Image.open(io.BytesIO(raw)).convert("RGBA")
img.save(out_path, format="PNG")
except Exception as e:
raise HTTPException(400, f"Invalid input image: {e}") from e
def _write_bridge_mask(raw: bytes, out_path: Path) -> None:
try:
from PIL import Image
import io
except Exception as e:
raise HTTPException(503, "Pillow is required for MLX image edit bridge masks.") from e
try:
img = Image.open(io.BytesIO(raw))
if img.mode == "RGBA":
# OpenAI edits mask convention: transparent = regenerate.
alpha = img.getchannel("A")
mask = alpha.point(lambda p: 255 if p < 128 else 0)
else:
mask = img.convert("L")
mask.save(out_path, format="PNG")
except Exception as e:View on GitHub (pinned to f9235ebbf1)
Solutions
- Validate the file locally before upload: open it with PIL and re-save as PNG
- Confirm the multipart field named 'image' actually contains the image and is fully transmitted
- If the file is HEIC/AVIF/etc., convert it to PNG or JPEG client-side first
- Check server temp directory is writable if uploads are known-good
Example fix
# before
files = {'image': open('possibly-broken.png','rb')}
# after
from PIL import Image
img = Image.open('possibly-broken.png'); img.verify()
files = {'image': open('known-good.png','rb')} Defensive patterns
Strategy: validation
Validate before calling
from PIL import Image
import io
img = Image.open(io.BytesIO(raw_bytes)); img.verify() # raises before upload if broken
img = Image.open(io.BytesIO(raw_bytes)).convert('RGB')
img.save('/tmp/out.png', format='PNG') # exercise save too Try / catch
try:
r = requests.post(f'{base}/v1/images/edits', files=files)
r.raise_for_status()
except requests.HTTPError as e:
if e.response.status_code == 400:
fix_and_recompress_image(); retry_once() Prevention
- Always verify()+re-save images as PNG client-side
- Never trust file extensions; validate magic bytes
- Stream multipart from a real file object, not a text buffer
When it happens
Trigger: Uploading a corrupted file, a non-image file (e.g. PDF/text renamed .png), a truncated upload, or an image format PIL cannot decode; occasionally an unwritable temp path makes img.save raise the same way.
Common situations: Client sends base64-decoded garbage or empty bytes; multipart field order sends the wrong file into 'image'; progressive/interrupted upload; image saved with a .png extension but actually WebP/HEIC and PIL lacks the decoder plugin.
Related errors
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/36f253720819e7d7.
Report an issue: GitHub.