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

  1. Reduce output size (export as JPEG) and retry if the status is 413.
  2. Check that the server's gallery storage path exists and is writable.
  3. Free disk space if the body text mentions ENOSPC/write failure.
  4. 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

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


AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14). Data as JSON: /api/errors/afb1bbca5213d1ce. Report an issue: GitHub.