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
- Send a proper Origin header on the request (e.g. 'Origin: https://budget.example.com')
- Include the scheme (http:// or https://) in the Origin value
- Check that your reverse proxy forwards Origin rather than removing it
- 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
- Always send an absolute http(s) Origin header when calling GoCardless link endpoints
- Verify reverse proxies forward Origin unchanged
- Test with curl using -H 'Origin: ...' rather than omitting it
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
- Single file ID is required
- Account with ID ${upgradingId} not found.
- Invalid GoCardless identifier: ${String(id)}
- invalid-file-id
- invalid-file-id
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/08a659a4d4da23c3.
Report an issue: GitHub.