odysseus-dev/odysseus · error · Error

Login failed

Error message

Login failed

What it means

Fallback error from doLogin() when POST /api/auth/login returns non-2xx. The server's data.detail is preferred (e.g. 'invalid credentials'); this literal appears only when the body lacks detail. The thrown error is caught by the outer try and rendered in the login form.

Source

Thrown at static/login.html:499

        fetch('/api/auth/features', { credentials: 'same-origin' }).then(r => r.json()),
        fetch('/api/auth/settings', { credentials: 'same-origin' }).then(r => r.json()),
      ]).then(([sess, feat, sett]) => {
        sessionStorage.setItem('ody-prefetch-sessions', JSON.stringify(sess));
        sessionStorage.setItem('ody-prefetch-features', JSON.stringify(feat));
        sessionStorage.setItem('ody-prefetch-settings', JSON.stringify(sett));
      }).catch(() => {}).finally(() => { window.location.replace('/'); });
    }
    async function doLogin(totpCode) {
      const loginBody = { username, password, remember };
      if (totpCode) loginBody.totp_code = totpCode;
      const res = await fetch('/api/auth/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        credentials: 'same-origin',
        body: JSON.stringify(loginBody)
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.detail || 'Login failed');
      return data;
    }
    try {
      let data = await doLogin();
      // 2FA required — show TOTP input
      if (data.requires_totp) {
        submitBtn.disabled = false;
        // Only add TOTP input once
        if (document.getElementById('totp-input')) return;
        form._totpMode = true;
        const totpWrap = document.createElement('div');
        totpWrap.style.cssText = 'margin-top:12px;';
        totpWrap.innerHTML = '<label for="totp-input" style="font-size:0.85em;opacity:0.7;display:block;margin-bottom:4px;">2FA Code</label><input type="text" id="totp-input" placeholder="Enter 6-digit code" aria-label="Two-factor authentication code" autocomplete="one-time-code" inputmode="numeric" maxlength="8" style="width:100%;padding:10px 12px;background:var(--bg);color:var(--fg);border:1px solid var(--border);border-radius:8px;font-size:14px;box-sizing:border-box;text-align:center;letter-spacing:4px;">';
        const formEl = submitBtn.parentElement;
        formEl.insertBefore(totpWrap, submitBtn);
        const totpInput = document.getElementById('totp-input');
        totpInput.focus();
        submitBtn.textContent = 'Verify';

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Verify username and password; the specific server reason usually replaces this message
  2. If the generic message persists, inspect the raw response body/status in devtools (proxy or 5xx issue)
  3. Confirm the account exists and is not locked; reset password if needed
  4. Ensure cookies/JS are enabled so the login POST and session work
Defensive patterns

Strategy: try-catch

Try / catch

try { const data = await doLogin(); if (data.requires_totp) showTotpStep(); } catch (err) { errEl.textContent = err.message || 'Login failed'; submitBtn.disabled = false; }

Prevention

When it happens

Trigger: Wrong username/password (backend returns detail like 'Invalid credentials'), account locked, or a non-JSON response (gateway error) leaving data.detail undefined.

Common situations: Typo in credentials; password changed elsewhere; expired/locked account; API fronted by a proxy that returns HTML errors.

Related errors


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