odysseus-dev/odysseus · error · HTTPException
SAM mask failed: {exc}
Error message
SAM mask failed: {exc} What it means
HTTP 500 catch-all for the SAM smart-mask endpoint: any exception other than an HTTPException during processor encoding, model inference (torch), post_process_masks, or mask-to-PIL conversion is logged with logger.exception and re-raised as 'SAM mask failed: {exc}'. The chained exception preserves the root cause.
Source
Thrown at routes/gallery/gallery_routes.py:1961
mask_img = Image.fromarray(mask_array, mode="L")
if mask_img.size != image.size:
mask_img = mask_img.resize(image.size, Image.NEAREST)
bbox = mask_img.getbbox()
result = {
"mask": _pil_image_to_b64(mask_img),
"bbox": list(bbox) if bbox else None,
"model": backend["model_id"],
"device": device,
}
if grounded:
result["grounding"] = grounded
return result
except HTTPException:
raise
except Exception as exc:
logger.exception("smart_mask failed")
raise HTTPException(500, f"SAM mask failed: {exc}") from exc
@router.post("/api/image/remove-bg")
async def remove_background(request: Request):
"""Remove background from an image. If the client passes a `hint_mask`
(white-where-the-user-wants-the-subject PNG, same dims as the
image), we constrain the output:
1. Crop the image to the mask's bounding box (with padding) so
the model only sees the region the user cares about.
2. Run rembg on that crop.
3. Paste the result back at the original offset.
4. Multiply the final alpha by the user's mask, so anything
outside the hint becomes transparent regardless of what the
model thought was foreground.
"""
require_privilege(request, "can_generate_images")
body = await request.json()
image_b64 = body.get("image")View on GitHub (pinned to f9235ebbf1)
Solutions
- Read the server log's 'smart_mask failed' traceback — the message suffix {exc} plus the stack identify the true failure
- For CUDA OOM, downscale the image before sending or free GPU memory / use the CPU device
- Pin compatible torch/transformers versions per requirements.txt and re-download model weights
- Retry once after verifying the image decodes locally with PIL
Example fix
# client: surface the server's chained cause
resp = requests.post(url, json=payload)
if resp.status_code == 500 and 'SAM mask failed' in resp.text:
logging.error('server traceback: %s', resp.text) Defensive patterns
Strategy: try-catch
Validate before calling
# pre-flight the pipeline's fragile assumptions
from PIL import Image
img = Image.open(io.BytesIO(base64.b64decode(b64)))
img.convert('RGB').save(io.BytesIO(), format='PNG') # decodable check
if img.width * img.height > 4_000_000:
img.thumbnail((2048, 2048)) # reduce CUDA OOM risk Try / catch
try:
result = smart_mask(image=b64, points=pts)
except HTTPException as e:
if e.status_code == 500:
logger.exception('SAM failed; server log has full traceback')
if 'out of memory' in str(e.detail):
result = smart_mask(image=downscaled_b64, points=pts) # one retry, smaller
else:
raise Prevention
- Downscale large images before sending to bound GPU memory
- Pre-warm/download model weights at server startup so first-request downloads can't fail mid-inference
- Pin torch/transformers versions in requirements and test the SAM route in CI against them
When it happens
Trigger: POST a valid prompt when CUDA OOMs during model(**model_inputs), transformers version incompatibility in post_process_masks, corrupt image that PIL opens but processor rejects, or model weights failing to download mid-request.
Common situations: Large images on a small GPU (OOM); mismatched transformers/torch versions after an upgrade; first-request model download interrupted by a proxy; device mismatch after toggling CUDA availability.
Related errors
- data.detail || data.error || `Mask failed (${res.status})`
- Found ${data.grounding.label || 'object'}, but SAM returned
- Cleanup preview generation failed
- Provide at least one point, box, or object text
- str(e)
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/94e7cd88b609f0ea.
Report an issue: GitHub.