actualbudget/actual · error

Invalid Origin header

Error message

Invalid Origin header

What it means

validateOrigin parses the request's Origin header with new URL(). If the header is missing/empty or not a parseable absolute URL, it throws Error('Invalid Origin header') before the GoCardless redirect flow can compute a redirect host.

Source

Thrown at packages/sync-server/src/app-gocardless/app-gocardless.ts:37

  GoCardlessAccountId,
  GoCardlessInstitutionId,
  GoCardlessRequisitionId,
} from './gocardless-node.types';
import { goCardlessService } from './services/gocardless-service';
import { handleError } from './util/handle-error';

function isRecord(value: unknown): value is Record<string, unknown> {
  return typeof value === 'object' && value !== null;
}

const ELECTRON_APP_ORIGIN = 'app://actual';

function validateOrigin(origin: string | undefined) {
  let url;
  try {
    url = new URL(origin ?? '');
  } catch {
    throw new Error('Invalid Origin header');
  }
  if (url.protocol !== 'http:' && url.protocol !== 'https:') {
    throw new Error('Invalid Origin header');
  }
  return url.origin;
}

function resolveRedirectHost(req: Request) {
  const { origin } = req.headers;
  const host = req.get('host');
  if (origin === ELECTRON_APP_ORIGIN && host) {
    return `${req.protocol}://${host}`;
  }
  return validateOrigin(origin);
}

const SAFE_ID = /^[a-zA-Z0-9_-]+$/;
function sanitizeId<T extends string = string>(id: unknown): T {

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Send a proper Origin header on the request (e.g. 'Origin: https://budget.example.com')
  2. Include the scheme (http:// or https://) in the Origin value
  3. Check that your reverse proxy forwards Origin rather than removing it
  4. Note protocol must be http: or https: — any other scheme is rejected

Example fix

// before
curl -X POST https://server/gocardless/create-link
// after
curl -X POST -H 'Origin: https://budget.example.com' https://server/gocardless/create-link
Defensive patterns

Strategy: validation

Validate before calling

function hasValidOrigin(origin) {
  if (!origin) return false;
  try { const u = new URL(origin); return u.protocol === 'http:' || u.protocol === 'https:'; }
  catch { return false; }
}
if (!hasValidOrigin(window.location.origin)) throw new Error('fix Origin before calling');

Try / catch

try {
  const res = await fetch(`${server}/gocardless/create-link`, { headers: { Origin: location.origin } });
} catch (e) {
  if (e.message === 'Invalid Origin header') {
    console.error('Origin header missing or malformed; send an absolute http(s) URL');
  } else throw e;
}

Prevention

When it happens

Trigger: Calling the GoCardless link endpoints without sending an Origin header (curl/scripts, server-side fetches), or sending a malformed Origin (e.g. 'localhost:3001' without scheme, garbage values).

Common situations: Testing the endpoint with curl/Postman which omit Origin by default; reverse proxies stripping the Origin header; native clients constructing the Origin manually and forgetting 'https://'

Related errors


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