odysseus-dev/odysseus · error · Error
Server error
Error message
Server error
What it means
Generic failure for the test-reminder sender. It POSTs the reminder payload; the first check throws data.detail || 'Server error' when res is not OK. This is the HTTP-level failure branch — channel-specific delivery checks (email/ntfy/webhook) run only after it passes.
Source
Thrown at static/js/settings.js:2705
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
note_id: 'test-' + Date.now(),
title: 'Test Reminder',
body: 'This is a test reminder to verify your settings are working.',
channel: channelSel.value,
// Mirror the in-UI AI Synthesis toggle + persona so the test never
// races a pending save and lets the user preview changes before
// hitting Save.
llm_synthesis: !!(llmToggle && llmToggle.checked),
llm_persona: (personaSel && personaSel.value) || '',
...(channelSel.value === 'webhook' ? {
webhook_integration_id: webhookIntgSel?.value || '',
webhook_payload_template: webhookTemplateIn?.value.trim() || '',
} : {}),
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.detail || 'Server error');
if (channelSel.value === 'email' && !data.email_sent) {
throw new Error(data.email_error || 'Email reminder was not sent');
}
if (channelSel.value === 'ntfy' && !data.ntfy_sent) {
throw new Error(data.ntfy_error || 'ntfy reminder was not sent');
}
if (channelSel.value === 'webhook' && !data.webhook_sent) {
const activeChannel = data.channel ? ` (server used channel: "${data.channel}")` : '';
throw new Error((data.webhook_error || 'Webhook reminder was not sent') + activeChannel);
}
let status = 'Delivered via ' + channelSel.value;
if (data.synthesis) status += ' (AI: "' + data.synthesis.slice(0, 60) + '...")';
if (data.email_sent) status += ' — email sent';
if (data.ntfy_sent) status += ' — ntfy sent';
if (data.webhook_sent) status += ' — webhook sent';
if (testMsg) { testMsg.textContent = status; testMsg.style.color = 'var(--green, #50fa7b)'; }
// Also fire a browser notification so user can see it
if ('Notification' in window && Notification.permission === 'granted') {View on GitHub (pinned to f9235ebbf1)
Solutions
- Read data.detail from the response in devtools — it names the server-side reason
- Verify the selected channel and its integration are configured server-side
- Re-authenticate if 401
- Default the fallback to include res.status: `Server error (HTTP ${res.status})`
Example fix
// before
const data = await res.json();
if (!res.ok) throw new Error(data.detail || 'Server error');
// after
const data = await res.json().catch(() => ({}));
if (!res.ok) throw new Error(data.detail || `Server error (HTTP ${res.status})`); Defensive patterns
Strategy: try-catch
Validate before calling
if (!['email','ntfy','webhook'].includes(channelSel.value)) return;
if (!navigator.onLine) { if (testMsg) testMsg.textContent = 'Offline'; return; } Try / catch
try { const res = await fetch(...); const data = await res.json().catch(() => ({})); if (!res.ok) throw new Error(data.detail || `Server error (HTTP ${res.status})`); ... } catch (e) { if (testMsg) { testMsg.textContent = e.message; testMsg.style.color = 'var(--red)'; } } Prevention
- Guard res.json() so network failures still produce a readable error
- Confirm the selected channel's integration exists before testing
- Include res.status in the fallback message
- Disable the test button while a test is in flight
When it happens
Trigger: POST returns 4xx/5xx with detail (validation error, missing integration, bad channel, auth expired) or with an empty detail field so 'Server error' is used; network rejection also lands here after res.json() fails.
Common situations: Reminder integrations (SMTP/ntfy/webhook) not configured on the server; invalid channel selection; expired auth; downstream validation rejecting the test payload.
Related errors
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/9be346a961b87ab8.
Report an issue: GitHub.