odysseus-dev/odysseus · error · Error
HTTP ${saveRes.status}: ${errBody.substring(0, 120)}
Error message
HTTP ${saveRes.status}: ${errBody.substring(0, 120)} What it means
Thrown by 'Save as copy' in galleryEditor.js when POST /api/gallery/upload returns non-ok. Unlike the replace flow it reads the raw body as text and truncates to 120 chars, so HTML error pages from proxies appear inline. On success it clears the server-side draft; on failure the draft is kept.
Source
Thrown at static/js/galleryEditor.js:3698
const flat = flatten();
const ext = (state.originalExt || 'png').toLowerCase();
const isJpeg = ext === 'jpg' || ext === 'jpeg';
const mime = isJpeg ? 'image/jpeg' : 'image/png';
const quality = isJpeg ? 0.92 : undefined;
blob = await new Promise((resolve, reject) => {
flat.toBlob(b => b ? resolve(b) : reject(new Error('Canvas encode failed')), mime, quality);
});
const formData = new FormData();
formData.append('file', blob, `edited.${isJpeg ? 'jpg' : 'png'}`);
const saveRes = await fetch(`${API_BASE}/api/gallery/upload`, {
method: 'POST',
credentials: 'same-origin',
body: formData,
});
if (!saveRes.ok) {
const errBody = await saveRes.text().catch(() => '');
throw new Error(`HTTP ${saveRes.status}: ${errBody.substring(0, 120)}`);
}
const totalMs = Math.round(performance.now() - t0);
window.dispatchEvent(new CustomEvent('gallery-refresh'));
if (uiModule) uiModule.showToast(`Saved copy to gallery (${(blob.size / 1024 / 1024).toFixed(1)}MB · ${(totalMs / 1000).toFixed(1)}s)`, 4000);
savedOk = true;
if (state.draftId) {
_clearDraftServer(state.draftId);
state.draftId = null;
}
} catch (e) {
console.error('[save-as-copy] error:', e);
const sizeMB = blob ? ` (${(blob.size / 1024 / 1024).toFixed(1)}MB)` : '';
let msg = e?.message || 'unknown';
if (e?.name === 'TypeError' || /fetch|network|load failed/i.test(msg)) {
msg = `network dropped${sizeMB} — check connection`;
} else {
msg += sizeMB;
}View on GitHub (pinned to f9235ebbf1)
Solutions
- Reduce output size (export as JPEG) and retry if the status is 413.
- Check that the server's gallery storage path exists and is writable.
- Free disk space if the body text mentions ENOSPC/write failure.
- Refresh auth and retry; the editor draft is preserved so no work is lost.
Defensive patterns
Strategy: fallback
Try / catch
try { if (!saveRes.ok) throw new Error(`HTTP ${saveRes.status}`); } catch (e) { keep draft on server; suggest re-encode as JPEG and retry; } Prevention
- Only clear the server draft after a confirmed successful upload
- Truncate but also log the full error body for diagnosis
- Shrink exports (JPEG quality) before upload on 413
When it happens
Trigger: Uploading an edited copy when the gallery upload directory is unwritable; a 413 from a fronting proxy on a large PNG; a 500 from an upload handler (disk full, filename collision); auth cookie missing.
Common situations: Same body-size pitfalls as error 84; galleries on network mounts that dropped; server restarted mid-edit so the upload endpoint's temp dir is gone.
Related errors
- HTTP ${resp.status}${detail ? `: ${detail}` : ''}
- Not your image
- No image provided
- statusText
- Server returned ${res.status}
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/afb1bbca5213d1ce.
Report an issue: GitHub.