odysseus-dev/odysseus · error · Error

d.error || 'Failed to create calendar'

Error message

d.error || 'Failed to create calendar'

What it means

HTTP 500 from GET /{file_id}/vision when analyze_image_with_vl (src/document_processor.py:390) raises while computing OCR/description — e.g. the vision model is unreachable, credentials invalid, or image decoding fails. The underlying exception is interpolated into the message ('Vision analysis failed: {e}') after being logged, so the response carries the root cause. The cache write afterward is best-effort and never 500s.

Source

Thrown at static/js/calendar.js:2625

    if (_open) _render();
  });
  _sunBtn?.addEventListener('click', () => {
    _weekStartSun = true;
    localStorage.setItem('cal-week-start', 'sun');
    _applyWeekStartActive();
    if (_open) _render();
  });

  // Create a new (local) calendar. Defaults the name + next palette color, then
  // reopens the panel so the user can rename it inline and pick a color.
  overlay.querySelector('#cal-settings-add')?.addEventListener('click', async (e) => {
    const btn = e.currentTarget;
    btn.disabled = true;
    const color = COLORS[_calendars.length % COLORS.length];
    try {
      const r = await fetch(`${API_BASE}/api/calendar/calendars?name=${encodeURIComponent('New calendar')}&color=${encodeURIComponent(color)}`, { method: 'POST', credentials: 'same-origin' });
      const d = await r.json().catch(() => ({}));
      if (!r.ok || !d.ok) throw new Error(d.error || 'Failed to create calendar');
      _calendars.push({ name: d.name, href: d.id, color: d.color });
      _allEvents = {}; _fetchedRanges = []; localStorage.removeItem(LS_KEY);
      _render();
      cleanup();
      _showCalSettings();
      // Focus the new row's name field so it's ready to rename.
      setTimeout(() => {
        const rows = document.querySelectorAll('#cal-settings-list .cal-settings-row');
        const last = rows[rows.length - 1];
        const nm = last?.querySelector('.cal-s-name');
        if (nm) { nm.focus(); nm.select(); }
      }, 30);
    } catch (err) {
      btn.disabled = false;
      if (window.showError) window.showError(err.message || 'Failed to create calendar');
      else console.error(err);
    }
  });

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Read the response body / server log — the embedded {e} names the actual failure (auth error, timeout, decode error).
  2. Fix the vision model configuration (endpoint URL, API key, quota) in the environment and retry without force=1 so any existing cache is used.
  3. If the image itself is corrupt, re-upload the source file; a partially-written upload will fail decode every time.
  4. Avoid force=1 in automated flows — it bypasses the cache and exposes every request to model availability.
  5. Treat this as transient where applicable: retry with backoff after restoring model access.

Example fix

// before
const r = await fetch(`/api/upload/${id}/vision?force=1`);

// after
const r = await fetch(`/api/upload/${id}/vision`); // prefer cache; force only on user action
Defensive patterns

Strategy: retry

Try / catch

async function getVisionText(id, { force = false, retries = 2 } = {}) {
  for (let i = 0; i <= retries; i++) {
    const r = await fetch(`/api/upload/${id}/vision${force ? '?force=1' : ''}`, { credentials: 'include' });
    if (r.ok) return (await r.json()).text;
    if (r.status === 500 && i < retries) { await sleep(1000 * 2 ** i); continue; }
    throw new Error(`vision failed: ${await r.text()}`); // body carries root cause
  }
}

Prevention

When it happens

Trigger: First (uncached) GET /vision for an image while the vision model API is down, the API key is invalid/quota-exhausted, the image is corrupt so decode fails, or the model returns a payload the parser rejects. Cached entries (UPLOAD_DIR/.vision/{id}.txt) never hit this path unless force=1.

Common situations: Missing/rotated VL model credentials in deployment env; vision provider rate limit or outage; corrupt upload (partial write) so PIL/opening the file throws; forcing recompute with ?force=1 during an outage when a good cache existed.

Related errors


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