odysseus-dev/odysseus · warning · Error
HTTP ' + r.status
Error message
HTTP ' + r.status
What it means
HTTP 403 from GET /{file_id}/vision when authentication is configured and effective_user(request) returns no authenticated user. The vision route mirrors the download route's owner-or-admin policy, and anonymous callers are rejected before cache lookup or OCR computation (vision calls can be expensive, so gating early matters).
Source
Thrown at static/js/calendar.js:258
// Per-event color override (including the bg:<url> sentinel for custom
// backgrounds) wins over the parent calendar's default hex.
color: (data.color !== undefined && data.color !== null) ? data.color : (cal?.color || ''),
};
}
// v2 review error-handling MEDs: every fetch here previously checked
// only `.then(r => r.json())` with no `r.ok` test. A 500/404 still
// resolved the promise and the optimistic state got promoted to truth.
// All three flows now inspect `r.ok` and roll back the optimistic
// state + surface a toast on the failure path.
async function _createEvent(data) {
const tempUid = 'temp-' + Date.now() + '-' + Math.random().toString(36).slice(2, 8);
_allEvents[tempUid] = _optimisticEvent(data, tempUid);
fetch(`${API_BASE}/api/calendar/events`, {
method: 'POST', credentials: 'same-origin',
headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data),
}).then(async r => {
if (!r.ok) throw new Error('HTTP ' + r.status);
return r.json();
}).then(d => {
if (d.uid) {
delete _allEvents[tempUid];
_allEvents[d.uid] = _optimisticEvent(data, d.uid);
_saveCache && _saveCache();
if (_open) _render();
}
}).catch((e) => {
delete _allEvents[tempUid];
if (_open) _render();
if (window.uiModule) window.uiModule.showError('Failed to create event: ' + (e?.message || 'unknown'));
});
return { uid: tempUid };
}
async function _updateEvent(uid, data) {
const merged = { ...(_allEvents[uid] || {}), ...data };View on GitHub (pinned to f9235ebbf1)
Solutions
- Send valid credentials with the request (session cookie or token) — same auth context as the chat UI uses.
- Ensure the client only calls /vision after a successful auth handshake.
- Re-login if the session expired; check cookie attributes if the call comes from a different origin.
- Confirm whether auth is intentionally configured — an unexpected users/auth config flips this endpoint from open to 403.
Defensive patterns
Strategy: validation
Validate before calling
const session = await getSession();
if (!session?.user) { await login(); } // then call /vision Try / catch
try {
const r = await fetch(`/api/upload/${id}/vision`, { credentials: 'include' });
if (r.status === 403) { promptLogin(); return; }
} catch (e) { /* offline handling */ } Prevention
- Only trigger OCR prefetch after login completes
- Include session credentials on all /vision calls
When it happens
Trigger: GET /api/upload/{id}/vision without a session/credential while auth is configured; expired session token; server-side fetch to the vision endpoint missing the auth cookie.
Common situations: Frontend prefetching vision text before login completes; incognito access to a shared link; token invalidation after an auth-secret rotation.
Related errors
- Server error ' + res.status
- Not authenticated
- Admin only
- This endpoint requires an API token
- API token is not scoped for chat
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/a3d89fa1c3a05dd8.
Report an issue: GitHub.