odysseus-dev/odysseus · warning · HTTPException
No image
Error message
No image
What it means
HTTP 400 raised by POST /api/gallery/ai-upscale when the multipart form contains no 'image' field. Unlike the replace endpoint this check is only `if not file`, so a string value in the field would pass here and fail later in read_upload_limited; a wholly absent field fails immediately. The route also requires the can_generate_images privilege first.
Source
Thrown at routes/gallery/gallery_routes.py:568
img_path.write_bytes(content)
img.file_hash = hashlib.sha256(content).hexdigest()
img.file_size = len(content)
img.width, img.height = rotated.size
db.commit()
return {"ok": True, "width": img.width, "height": img.height}
finally:
db.close()
# ---- POST /api/gallery/ai-upscale ----
@router.post("/api/gallery/ai-upscale")
async def gallery_ai_upscale(request: Request):
"""AI upscale using img2img with the diffusion server."""
import base64, httpx
user = require_privilege(request, "can_generate_images")
form = await request.form()
file = form.get("image")
if not file: raise HTTPException(400, "No image")
scale = int(form.get("scale", "2"))
image_bytes = await read_upload_limited(file, GALLERY_TRANSFORM_UPLOAD_MAX_BYTES, "Image upload")
b64 = base64.b64encode(image_bytes).decode()
# Find image endpoint
db = SessionLocal()
try:
ep = _first_visible_image_endpoint(db, user)
finally:
db.close()
if not ep:
raise HTTPException(400, "No image generation endpoint configured. Add one in Settings → Add Models.")
base_url = ep.base_url.rstrip("/")
if not base_url.endswith("/v1"):
base_url += "/v1"View on GitHub (pinned to f9235ebbf1)
Solutions
- Append the file as 'image' in multipart/form-data.
- Validate the file is selected before enabling the upscale button.
- Note the privilege gate: the user must have can_generate_images or the request fails earlier with 403.
Example fix
// before
fd.append('img', file); // wrong name -> 400
// after
fd.append('image', file); fd.append('scale', '2'); Defensive patterns
Strategy: validation
Validate before calling
if (!file) return showError('Choose an image to upscale');
const fd = new FormData(); fd.append('image', file); fd.append('scale', '2'); Type guard
const hasImagePart = (fd) => fd.get('image') != null; Try / catch
try { await upscale(fd); } catch (e) { if (e.status === 400) showError('Attach the image in the "image" field'); } Prevention
- Reuse a single correctly-keyed FormData helper for all transform endpoints
- Disable action until a file is picked
- Remember can_generate_images is checked first (403 otherwise)
When it happens
Trigger: POST /api/gallery/ai-upscale with an empty form, a JSON body, or a FormData missing an 'image' part.
Common situations: Frontend reusing a FormData built for a different endpoint; file picker cleared before submit; curl without -F.
Related errors
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/8794ed2c5c239b4e.
Report an issue: GitHub.