{"record":{"id":"4bed0afc859142b2","repo":"odysseus-dev/odysseus","slug":"inpaint-request-failed","errorCode":null,"errorMessage":"Inpaint request failed","messagePattern":"Inpaint request failed","errorType":"http","errorClass":"HTTPException","httpStatus":null,"severity":"error","filePath":"routes/gallery/gallery_routes.py","lineNumber":1499,"sourceCode":"                        # Odysseus diffusion_server.py has a dedicated\n                        # /images/inpaint route that can derive/fallback to\n                        # inpaint, img2img crop+composite, or txt2img\n                        # crop+composite. Fall through to that route instead\n                        # of surfacing \"does not support image edits\".\n                        if r.status_code == 400 and \"does not support image edits\" in str(detail).lower():\n                            logger.info(\"inpaint_proxy self-hosted edits unsupported; falling back to /images/inpaint\")\n                        else:\n                            raise HTTPException(r.status_code, detail)\n                except HTTPException:\n                    raise\n                except Exception:\n                    logger.exception(\"inpaint_proxy: failed to prepare self-hosted edit request\")\n                    raise HTTPException(400, \"Failed to prepare inpaint request\")\n\n                r = await client.post(_join_checked_gallery_endpoint(base, \"/images/inpaint\"), json=body)\n                if r.status_code != 200:\n                    logger.error(\"inpaint_proxy diffusion: status %s\", r.status_code)\n                    raise HTTPException(r.status_code, \"Inpaint request failed\")\n                return r.json()\n        except httpx.TimeoutException:\n            raise HTTPException(504, \"Inpaint request timed out (240s)\")\n        except HTTPException:\n            raise\n        except Exception:\n            logger.exception(\"inpaint_proxy: request failed\")\n            raise HTTPException(502, \"Inpaint request failed\")\n\n    # ---- POST /api/image/harmonize — proper img2img call ----\n    # Earlier version routed through inpaint with a full-white mask, but\n    # most backends interpret \"100% mask coverage\" as \"regenerate from\n    # scratch using the prompt\", ignoring the source. Real img2img sends\n    # the image alongside a `strength` (denoising strength) and the model\n    # mixes that fraction of new noise into the existing pixels.\n    @router.post(\"/api/image/harmonize\")\n    async def harmonize_image(request: Request):\n        \"\"\"Harmonize = img2img. The model preserves (1 - strength) of the","sourceCodeStart":1481,"sourceCodeEnd":1517,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/gallery/gallery_routes.py#L1481-L1517","documentation":"Raised when the fallback POST to the self-hosted /v1/images/inpaint JSON endpoint returns a non-200 status. The upstream status code is forwarded with detail 'Inpaint request failed'; the route logs 'inpaint_proxy diffusion: status %s' first.","triggerScenarios":"The diffusion server's dedicated /images/inpaint route rejecting the JSON body: 422 (missing fields like image/mask/prompt), 500 (inpaint pipeline not available for the loaded checkpoint), or 400 (bad dimensions).","commonSituations":"Loaded checkpoint has no inpaint pipeline and the server's derive/fallback logic fails; the JSON body schema expected by diffusion_server.py differs from what the proxy sends; model loading/OOM on the GPU host.","solutions":["Check diffusion server logs for the failed /v1/images/inpaint call and its exception.","Verify the loaded model supports inpainting or that the server's img2img/txt2img crop+composite fallback is enabled.","Align the JSON fields the proxy sends (image, mask, prompt, model, size/n) with diffusion_server.py's /images/inpaint schema.","Free VRAM / restart the diffusion server if 500s stem from CUDA errors."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"async def inpaint_route_ready(base: str) -> bool:\n    try:\n        async with httpx.AsyncClient(timeout=10) as c:\n            r = await c.post(f\"{base}/v1/images/inpaint\", json={})\n            # 422 = route exists, payload rejected; 404 = route missing\n            return r.status_code != 404\n    except httpx.HTTPError:\n        return False","typeGuard":null,"tryCatchPattern":"try:\n    r = await client.post(\"/api/image/inpaint\", json=payload)\n    r.raise_for_status()\nexcept httpx.HTTPStatusError as e:\n    if e.response.status_code >= 500:\n        # upstream pipeline failure — check diffusion server logs\n        raise RuntimeError(\"diffusion inpaint failed server-side\") from e\n    raise","preventionTips":["Load a checkpoint with an inpaint pipeline (or ensure fallback is enabled) before using inpaint.","Keep proxy payload field names in sync with diffusion_server.py's schema.","Monitor diffusion server logs whenever the proxy returns non-200 details."],"tags":["self-hosted","diffusion-server","inpaint","upstream-error"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}