{"record":{"id":"6369e5d9495f78af","repo":"odysseus-dev/odysseus","slug":"pillow-is-required-for-mlx-image-edit-bridge-input","errorCode":null,"errorMessage":"Pillow is required for MLX image edit bridge inputs.","messagePattern":"Pillow is required for MLX image edit bridge inputs\\.","errorType":"http","errorClass":"HTTPException","httpStatus":503,"severity":"error","filePath":"scripts/mlx_image_server.py","lineNumber":178,"sourceCode":"def _weights_path(model: str) -> Path:\n    p = Path(model).expanduser()\n    if p.is_file():\n        return p\n    snap = _snapshot_path(model)\n    if snap.is_file():\n        return snap\n    candidates = sorted(snap.rglob(\"*.safetensors\"))\n    if not candidates:\n        raise HTTPException(500, f\"No safetensors weights found for {model} in {snap}\")\n    return candidates[0]\n\n\ndef _write_bridge_input_image(raw: bytes, out_path: Path) -> None:\n    try:\n        from PIL import Image\n        import io\n    except Exception as e:\n        raise HTTPException(503, \"Pillow is required for MLX image edit bridge inputs.\") from e\n    try:\n        img = Image.open(io.BytesIO(raw)).convert(\"RGBA\")\n        img.save(out_path, format=\"PNG\")\n    except Exception as e:\n        raise HTTPException(400, f\"Invalid input image: {e}\") from e\n\n\ndef _write_bridge_mask(raw: bytes, out_path: Path) -> None:\n    try:\n        from PIL import Image\n        import io\n    except Exception as e:\n        raise HTTPException(503, \"Pillow is required for MLX image edit bridge masks.\") from e\n    try:\n        img = Image.open(io.BytesIO(raw))\n        if img.mode == \"RGBA\":\n            # OpenAI edits mask convention: transparent = regenerate.\n            alpha = img.getchannel(\"A\")","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/scripts/mlx_image_server.py#L160-L196","documentation":"Raised by _write_bridge_input_image in scripts/mlx_image_server.py when importing PIL (Pillow) fails while preparing the input PNG for the MLX Swift colorize/inpaint bridge. Pillow is an optional runtime dependency; without it the edits/harmonize endpoints cannot decode and re-encode the uploaded image, so the server returns HTTP 503.","triggerScenarios":"POST /v1/images/edits or /v1/images/harmonize against a LaMa/MI-GAN/DDColor model when the launch Python lacks Pillow (import PIL raises).","commonSituations":"Minimal server venv where only fastapi/uvicorn were installed; PIL installed in a different environment than the one launching the server; Pillow broken by a mixed pip/conda install or an incompatible binary wheel after a Python upgrade.","solutions":["pip install Pillow in the environment that launches mlx_image_server.py","Verify with the same interpreter: python -c 'from PIL import Image'","Recreate the venv if Pillow is installed but fails to import (broken C extension)"],"exampleFix":"# before\npython scripts/mlx_image_server.py --model academictorrents/lama  # edits -> 503\n# after\npip install Pillow\npython scripts/mlx_image_server.py --model academictorrents/lama","handlingStrategy":"type-guard","validationCode":"import importlib.util\nif importlib.util.find_spec('PIL') is None:\n    raise SystemExit('Pillow missing in server env; pip install Pillow')","typeGuard":"def has_pillow() -> bool:\n    import importlib.util\n    return importlib.util.find_spec('PIL') is not None","tryCatchPattern":null,"preventionTips":["Add Pillow to the server's pinned requirements","Smoke-test the edits endpoint after any env rebuild","Launch the server via a script that asserts required imports"],"tags":["pillow","mlx","dependency","http-503"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}