odysseus-dev/odysseus · error · Error

HTTP ${res.status}

Error message

HTTP ${res.status}

What it means

Thrown when POST /api/email/extract-style fails: the guard `!res.ok || !data.success || !data.style` covers HTTP failure, a success=false body, and a missing style payload, with the message coming from data.error or 'HTTP <status>'. The status element then shows the failure reason.

Source

Thrown at static/js/emailLibrary.js:415

        wp = spinnerModule.createWhirlpool(14);
        wp.element.style.cssText = 'display:inline-block;vertical-align:-3px;margin-right:6px;';
        status.appendChild(wp.element);
        status.appendChild(document.createTextNode('Analyzing sent emails…'));
      } catch (_) {
        status.textContent = 'Analyzing sent emails…';
      }
    }
    try {
      const res = await fetch(emailApiUrl('/api/email/extract-style', {
        account_id: state._libAccountId || undefined,
      }), {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        credentials: 'include',
        body: JSON.stringify({ sample_count: 15 }),
      });
      const data = await res.json().catch(() => ({}));
      if (!res.ok || !data.success || !data.style) throw new Error(data.error || `HTTP ${res.status}`);
      if (styleEl) styleEl.value = data.style;
      if (status) status.textContent = 'Extracted';
      showToast?.('Email writing style extracted');
      setTimeout(() => { if (status) status.textContent = ''; }, 1800);
    } catch (err) {
      if (status) status.textContent = err?.message || 'Extract failed';
      showToast?.('Failed to extract email writing style');
    } finally {
      if (wp && wp.destroy) { try { wp.destroy(); } catch (_) {} }
      extractBtn.disabled = false;
      if (saveBtn) saveBtn.disabled = false;
    }
  });
}

function _hideEmailSettingsPage() {
  const modal = document.getElementById('email-lib-modal');
  const page = document.getElementById('email-lib-settings-page');

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Read the status text next to the button — it carries data.error when present
  2. Ensure the selected account has sent-folder messages to sample (sample_count: 15 needs history)
  3. Re-authenticate the email account if IMAP/token errors are indicated
  4. Retry after rate limits clear; verify account_id matches a configured account
Defensive patterns

Strategy: try-catch

Try / catch

try { const data = await res.json().catch(() => ({})); if (!res.ok || !data.success || !data.style) throw new Error(data.error || `HTTP ${res.status}`); ... } catch (err) { status.textContent = err?.message || 'Extract failed'; } finally { btn.disabled = false; }

Prevention

When it happens

Trigger: Clicking Extract in the email style settings: server cannot fetch enough sample messages (empty sent folder → no style), the account_id in state is stale, IMAP authentication fails mid-extraction, or the LLM call used to summarize style errors out.

Common situations: New account with too few sent messages; OAuth token expired between list and extract; provider rate limit on the style-summarization model; JSON parse failure handled as {} so data.error is undefined and the bare status shows.

Related errors


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