actualbudget/actual · error · Error

API request redirected

Error message

API request redirected

What it means

The server-side fetch wrapper detects `response.type === 'opaqueredirect'`, which happens when an authentication proxy redirected the request (typically because the session expired). It notifies the client via `api-fetch-redirected` and throws so the app can fully reload and hand control back to the server.

Source

Thrown at packages/loot-core/src/platform/server/fetch/index.ts:16

import * as connection from '#platform/server/connection';

export const fetch = async (
  input: RequestInfo | URL,
  options: RequestInit = {},
): Promise<Response> => {
  // Set redirect to manual so that we can detect and respond to redirects.
  if (!options.redirect) options.redirect = 'manual';

  const response = await globalThis.fetch(input, options);

  // Authentication proxies redirect when authentication has expired. In this case,
  // we want to fully reload and yeild control from the service worker back to the server.
  if (response.type === 'opaqueredirect') {
    connection.send('api-fetch-redirected');
    throw new Error(`API request redirected`);
  }

  return response;
};

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Log in again / refresh the page to re-establish the proxy session
  2. Check your auth proxy's session timeout and cookie configuration so long-running budgets aren't logged out
  3. Disable or bypass the auth proxy for the app's API routes if it interferes with server-side requests
Defensive patterns

Strategy: retry

Validate before calling

// re-check auth/session before long fetch sequences
const res = await fetch('/auth-check', { redirect: 'manual' });
if (res.type === 'opaqueredirect') location.reload(); // session expired

Try / catch

try {
  const res = await serverFetch(url, opts);
} catch (e) {
  if (e.message === 'API request redirected') {
    // session expired behind auth proxy — trigger full page reload / re-login
    window.location.href = '/login';
  } else throw e;
}

Prevention

When it happens

Trigger: `fetch()` (packages/loot-core/src/platform/server/fetch) with a `redirect: 'manual'` request where the server responds with a redirect — e.g. an auth proxy bouncing an expired session to a login page.

Common situations: Running Actual behind an auth proxy (oauth2-proxy, Authelia, etc.) whose session expired mid-use; the service worker forwarding a request that gets redirected instead of answered.

Related errors


AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29). Data as JSON: /api/errors/574b6fd90dc85386. Report an issue: GitHub.