odysseus-dev/odysseus · error · Error
statusText
Error message
statusText
What it means
Thrown when POST /api/image/inpaint (AI inpainting in the image editor) responds non-2xx. The code prefers a JSON body field detail or error and falls back to res.statusText — which is frequently empty under HTTP/2, leaving the user with a blank error.
Source
Thrown at static/js/editor/ai-inpaint.js:154
const dilatedMask = dilateMask(mergedMask, padPx);
const imageB64 = flatCanvas.toDataURL('image/png').split(',')[1];
const maskB64 = dilatedMask.toDataURL('image/png').split(',')[1];
const baseSnap = document.createElement('canvas');
baseSnap.width = state.imgWidth;
baseSnap.height = state.imgHeight;
baseSnap.getContext('2d').drawImage(flatCanvas, 0, 0);
const res = await fetch('/api/image/inpaint', {
method: 'POST', credentials: 'same-origin',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify((() => {
const sel = getSelectedAIEndpoint('inpaint');
return { image: imageB64, mask: maskB64, prompt, width: state.imgWidth, height: state.imgHeight, strength, feather: 0, _endpoint: sel.endpoint, _model: sel.model };
})()),
});
if (!res.ok) {
let errDetail = res.statusText;
try { const errBody = await res.json(); errDetail = errBody.detail || errBody.error || errDetail; } catch {}
throw new Error(errDetail);
}
const data = await res.json();
if (data.error) throw new Error(data.error);
if (!data.image) throw new Error('No image returned from inpaint endpoint');
// Load result as a new layer and clip with the user-drawn mask
// so only the inpainted region is visible. Cache the
// unfeathered (AI image + hard mask) on the layer so the live
// Feather slider can re-derive the alpha on each input event
// without re-running the model.
const resultImg = new Image();
resultImg.onload = () => {
if (!state.editorOpen) return; // user closed mid-decode
try {
saveState('Inpaint result');
// OpenAI returns at one of its allowed sizes (1024²,
// 1024×1536, 1536×1024) which often differs from our
// canvas. Scale to canvas size with smoothing so the
// inpaint blends in regardless of source dims.View on GitHub (pinned to f9235ebbf1)
Solutions
- Check the inpaint response body in the Network tab — the JSON detail usually names the upstream cause (missing key, provider 401, model name)
- Verify an AI endpoint/model is selected and configured for the inpaint tool (getSelectedAIEndpoint)
- Reduce image dimensions if the 413 body limit is the cause
- Include res.status in the fallback message so it is never blank
Example fix
// before
let errDetail = res.statusText;
// after
let errDetail = `HTTP ${res.status}`; Defensive patterns
Strategy: try-catch
Validate before calling
const sel = getSelectedAIEndpoint('inpaint');
if (!sel.endpoint) { uiModule.showToast('Select an AI endpoint first'); return; }
if (!imageB64 || !maskB64) { uiModule.showToast('Draw a mask before inpainting'); return; } Try / catch
if (!res.ok) { let errDetail = `HTTP ${res.status}`; try { const b = await res.json(); errDetail = b.detail || b.error || errDetail; } catch {} throw new Error(errDetail); } Prevention
- Use `HTTP ${res.status}` as fallback text, never bare statusText
- Verify an endpoint/model is selected before building the payload
- Cap exported image dimensions to stay under server body limits
- Surfaced upstream detail strings usually name the missing key/model — read them
When it happens
Trigger: Running Inpaint with a mask and prompt: the upstream AI provider key is missing/invalid (usually 500 with detail), the request payload exceeds the server's body limit (413), the selected custom endpoint in getSelectedAIEndpoint('inpaint') is unreachable, or credentials expired (401).
Common situations: No AI provider API key configured on the server; user-selected custom endpoint URL wrong or rate-limited; very large canvas producing a multi-MB base64 payload rejected by a proxy; statusText empty so 'Inpaint failed: ' shows nothing useful.
Related errors
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/42ca0b546d5c4e3a.
Report an issue: GitHub.