{"record":{"id":"4fcd93f6add68346","repo":"odysseus-dev/odysseus","slug":"no-image-generation-endpoint-configured","errorCode":null,"errorMessage":"No image generation endpoint configured.","messagePattern":"No image generation endpoint configured\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"routes/gallery/gallery_routes.py","lineNumber":626,"sourceCode":"\n        user = require_privilege(request, \"can_generate_images\")\n        form = await request.form()\n        file = form.get(\"image\")\n        prompt = form.get(\"prompt\", \"\")\n        strength = float(form.get(\"strength\", \"0.55\"))\n        if not file: raise HTTPException(400, \"No image\")\n\n        image_bytes = await read_upload_limited(file, GALLERY_TRANSFORM_UPLOAD_MAX_BYTES, \"Image upload\")\n        b64 = base64.b64encode(image_bytes).decode()\n\n        db = SessionLocal()\n        try:\n            ep = _first_visible_image_endpoint(db, user)\n        finally:\n            db.close()\n\n        if not ep:\n            raise HTTPException(400, \"No image generation endpoint configured.\")\n\n        base_url = ep.base_url.rstrip(\"/\")\n        if not base_url.endswith(\"/v1\"):\n            base_url += \"/v1\"\n\n        try:\n            async with httpx.AsyncClient(timeout=180) as client:\n                resp = await client.post(f\"{base_url}/images/generations\", json={\n                    \"prompt\": prompt,\n                    \"image\": b64,\n                    \"strength\": strength,\n                    \"response_format\": \"b64_json\",\n                })\n                if resp.status_code == 200:\n                    data = resp.json()\n                    img_data = data.get(\"data\", [{}])[0].get(\"b64_json\", \"\")\n                    if img_data:\n                        return {\"image\": img_data}","sourceCodeStart":608,"sourceCodeEnd":644,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/gallery/gallery_routes.py#L608-L644","documentation":"HTTP 400 raised by POST /api/gallery/style-transfer when no visible image-generation endpoint is configured for the user. Identical cause to the ai-upscale variant (553) with a shorter message: _first_visible_image_endpoint returned None, so there is no diffusion server to send the img2img request to.","triggerScenarios":"Running style transfer before any image endpoint is added, or when all configured endpoints are hidden from the requesting user.","commonSituations":"Post-install onboarding gap; endpoint visibility scoped per user or role; environment where the models table was cleared.","solutions":["Configure an image-generation endpoint in Settings with a valid base_url.","Ensure endpoint visibility includes the requesting user.","Surface a setup prompt in the UI when this 400 arrives instead of showing a generic failure."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const eps = await getVisibleImageEndpoints();\nif (!eps.length) { showSetupGuide('Configure an image generation endpoint'); return; }","typeGuard":"const hasImageEndpoint = (eps) => Array.isArray(eps) && eps.length > 0;","tryCatchPattern":"try { await styleTransfer(fd); } catch (e) { if (e.status === 400 && /endpoint/.test(e.message)) redirectToSettings(); }","preventionTips":["Add an image endpoint before advertising AI features","Check endpoint visibility for the acting user","Validate base_url reaches the diffusion server's /v1"],"tags":["http","configuration","gallery","style-transfer","endpoint"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}