odysseus-dev/odysseus · error · HTTPException

Pillow is required for MLX image edit bridge masks.

Error message

Pillow is required for MLX image edit bridge masks.

What it means

Raised by _write_bridge_mask in scripts/mlx_image_server.py when importing PIL fails while normalizing the uploaded mask PNG for the inpainting bridge (sibling of the input-image Pillow check). Without Pillow the server cannot apply the OpenAI alpha-transparency mask convention, so it returns HTTP 503.

Source

Thrown at scripts/mlx_image_server.py:191

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:
        raise HTTPException(400, f"Invalid mask image: {e}") from e


def _run_bridge(cmd: list[str]) -> None:
    env = os.environ.copy()
    proc = subprocess.run(cmd, env=env, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    if proc.returncode != 0:
        detail = (proc.stderr or proc.stdout or "MLX Swift bridge failed").strip()

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. pip install Pillow in the server's launch environment
  2. Verify import with the exact interpreter (python -c 'from PIL import Image')
  3. Reinstall Pillow if the import fails with an OSError about the C extension
Defensive patterns

Strategy: type-guard

Validate before calling

import importlib.util
assert importlib.util.find_spec('PIL'), 'install Pillow before serving edits'

Type guard

def has_pillow() -> bool:
    import importlib.util
    return importlib.util.find_spec('PIL') is not None

Prevention

When it happens

Trigger: POST /v1/images/edits with a mask file against a LaMa/MI-GAN model when the launch Python cannot import PIL.

Common situations: Same as 943: server venv missing Pillow, wrong interpreter used at launch, or a broken Pillow install; often both 943 and 945 trigger together since the input image is written before the mask.

Related errors


AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14). Data as JSON: /api/errors/8a844411fdead733. Report an issue: GitHub.