odysseus-dev/odysseus · warning · Error
data.error || 'failed'
Error message
data.error || 'failed'
What it means
Application-level error while staging an email attachment for forwarding: POST /api/email/compose-from-attachment/{uid}/{index} answered 200 but the JSON body has success falsy, so data.error (or 'failed') is thrown per attachment. Other attachments in the loop still attempt to stage; each failure shows a toast.
Source
Thrown at static/js/document.js:3177
if (!doc || doc.language !== 'email') return;
if (!fields?.forwardAttachments || !fields.sourceUid || !Array.isArray(fields.attachments) || fields.attachments.length === 0) return;
const sourceKey = `${fields.sourceFolder || 'INBOX'}:${fields.sourceUid}:${fields.attachments.map(a => a.index).join(',')}`;
if (doc._forwardedAttachmentSourceKey === sourceKey) return;
doc._forwardedAttachmentSourceKey = sourceKey;
if (!doc._composeAtts) doc._composeAtts = [];
const existingForwarded = new Set(doc._composeAtts.filter(a => a.forwardedSourceKey === sourceKey).map(a => String(a.sourceIndex)));
let added = 0;
for (const att of fields.attachments) {
const sourceIndex = String(att.index);
if (existingForwarded.has(sourceIndex)) continue;
try {
const folderQs = encodeURIComponent(fields.sourceFolder || 'INBOX');
const res = await fetch(`${API_BASE}/api/email/compose-from-attachment/${encodeURIComponent(fields.sourceUid)}/${encodeURIComponent(att.index)}?folder=${folderQs}`, {
method: 'POST',
credentials: 'same-origin',
});
const data = await res.json();
if (!data.success) throw new Error(data.error || 'failed');
doc._composeAtts.push({
token: data.token,
filename: data.filename || att.filename,
size: data.size || att.size || 0,
forwardedSourceKey: sourceKey,
sourceIndex,
});
added += 1;
} catch (err) {
console.error('Failed to stage forwarded attachment:', err);
if (uiModule) uiModule.showError(`Forward attachment failed: ${att.filename || 'attachment'}`);
}
}
if (added) {
_renderComposeAttachments();
clearTimeout(_autoSaveDebounce);
_autoSaveDebounce = setTimeout(() => { saveDocument({ silent: true }); }, 800);
}View on GitHub (pinned to f9235ebbf1)
Solutions
- Read data.error for the backend reason; usually the message is gone from the given folder
- Re-fetch/re-render the email document to refresh uid, folder, and attachment indices, then retry forward
- Ensure the folder query param matches the folder the message actually resides in
- Check backend temp storage health if errors mention tokens or disk
Defensive patterns
Strategy: validation
Validate before calling
if (!fields.sourceUid || !Array.isArray(fields.attachments)) { uiModule?.showError?.('Email data incomplete — reload the email'); return; }
if (!fields.sourceFolder) fields.sourceFolder = 'INBOX'; // be explicit about the default Try / catch
for (const att of fields.attachments) {
try {
const res = await fetch(url, { method: 'POST', credentials: 'same-origin' });
const data = await res.json().catch(() => ({}));
if (!res.ok || !data.success) {
console.warn(`Staging ${att.filename} failed:`, data.error || res.status);
continue; // skip this attachment, keep staging the rest
}
doc._composeAtts.push({ token: data.token, /* ... */ });
added += 1;
} catch (err) {
console.error('Failed to stage forwarded attachment:', err);
if (uiModule) uiModule.showError(`Forward attachment failed: ${att.filename || 'attachment'}`);
}
} Prevention
- JSON-parse defensively: a non-JSON error page would make res.json() throw and skip the !data.success check
- Skip-and-continue per attachment (loop already isolates failures — keep it) so one stale uid doesn't block the rest
- Check data.success AND res.ok together — 200 with success:false is the documented failure mode
When it happens
Trigger: 200 with {success:false,error:'message not found'} — the source uid was expunged or moved to another folder; attachment index stale after the message changed on the server; backend temp-token store full or unwritable.
Common situations: Message moved/deleted between opening the email and clicking forward; folder param defaulting to INBOX when the message lives elsewhere; backend cache directory permissions; concurrent forwarding of the same attachment.
Related errors
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/bdf7754a90691008.
Report an issue: GitHub.