remix-run/react-router · error · Error
`origin` header is not a valid URL. Aborting the action.
Error message
`origin` header is not a valid URL. Aborting the action.
What it means
Thrown by `throwIfPotentialCSRFAttack` when the `Origin` request header is a non-`null` string that cannot be parsed by `new URL(originHeader)`. The library aborts the action because it cannot safely classify the request as same-origin or cross-origin.
Source
Thrown at packages/react-router/lib/actions.ts:14
export function throwIfPotentialCSRFAttack(
request: Request,
allowedActionOrigins: string[] | undefined,
) {
let originHeader = request.headers.get("origin");
let originDomain: string | null = null;
try {
originDomain =
typeof originHeader === "string" && originHeader !== "null"
? new URL(originHeader).host
: originHeader;
} catch {
throw new Error(
`\`origin\` header is not a valid URL. Aborting the action.`,
);
}
let host = new URL(request.url).host;
if (originDomain && originDomain !== host) {
if (!isAllowedOrigin(originDomain, allowedActionOrigins)) {
// This seems to be an CSRF attack. We should not proceed with the action.
throw new Error(
"The `request.url` host does not match `origin` header from a forwarded " +
"action request. Aborting the action.",
);
}
}
}
// Implementation of micromatch by Next.js https://github.com/vercel/next.js/blob/ea927b583d24f42e538001bf13370e38c91d17bf/packages/next/src/server/app-render/csrf-protection.ts#L6
function matchWildcardDomain(domain: string, pattern: string) {View on GitHub (pinned to 1fd704a7da)
Solutions
- Inspect the raw `Origin` header the client is actually sending (browser devtools, proxy access logs).
- Fix the upstream proxy/client so Origin is either a well-formed absolute URL or omitted/`null`.
- If you control the client, send `Origin: https://your-app.example` or omit the header rather than send garbage.
- Reproduce with curl `-H 'Origin: https://valid.example'` to confirm the action succeeds once the header is well-formed.
Example fix
# before curl -X POST https://app/api -H 'Origin: ///' # after curl -X POST https://app/api -H 'Origin: https://app.example'
Defensive patterns
Strategy: validation
Validate before calling
function isValidOriginHeader(h: string | null): boolean {
if (h === null || h === 'null') return true;
try { new URL(h); return true; } catch { return false; }
}
// in your proxy/edge, sanitize before forwarding:
if (!isValidOriginHeader(request.headers.get('origin'))) {
return new Response('Bad Origin', { status: 400 });
} Type guard
function isParsableOrigin(h: string | null | undefined): h is string {
if (!h || h === 'null') return false;
try { new URL(h); return true; } catch { return false; }
} Try / catch
try {
await action({ request });
} catch (e) {
if (e instanceof Error && e.message.includes('`origin` header is not a valid URL')) {
return new Response('Invalid Origin header', { status: 400 });
}
throw e;
} Prevention
- Ensure reverse proxies forward `Origin` verbatim from the browser.
- Validate Origin at your edge before it reaches the app.
- Document for API clients that Origin must be a valid absolute URL or omitted.
When it happens
Trigger: A mutation request (POST/PUT/PATCH/DELETE) reaches a React Router action with an `Origin` header value that is not a valid URL and not the literal string `null`. Examples: a malformed proxy header, `Origin: //`, or a custom client setting garbage in Origin.
Common situations: Misconfigured reverse proxy rewriting/stripping Origin; a CDN injecting a malformed Origin; a security scanner or curl invocation sending `Origin: foo`; non-browser clients that set Origin to a non-URL token.
Related errors
AI-assisted analysis of remix-run/react-router@1fd704a7da (2026-08-12).
Data as JSON: /api/errors/6b3554626473d9ab.
Report an issue: GitHub.