sindresorhus/got · error · Error
The `url` option must stay on the same origin as `prefixUrl`
Error message
The `url` option must stay on the same origin as `prefixUrl` when `allowAbsoluteUrls` is false
What it means
Thrown at source/core/options.ts:1070 by `assertUrlHasSameOriginAsPrefixUrlIfNeeded`. Even when the per-call URL is technically relative and resolves under prefixUrl, if the resolved origin differs from the prefixUrl origin AND allowAbsoluteUrls is false, got throws. This catches cross-origin hops that arise from prefixUrl/path resolution (e.g. prefixUrl on `https://a.com` resolving a path that flips origin via redirect or option overrides) — the library treats origin changes as security-relevant because they may leak credentials or headers across trust boundaries.
Source
Thrown at source/core/options.ts:1070
export const assertUrlHasSameOriginAsPrefixUrlIfNeeded = (options: Options, url: URL): void => {
if (!options.prefixUrl || options.allowAbsoluteUrls) {
return;
}
let prefixUrl: URL;
try {
prefixUrl = new URL(options.prefixUrl);
} catch {
return;
}
if (isSameOrigin(prefixUrl, url)) {
return;
}
throw new Error('The `url` option must stay on the same origin as `prefixUrl` when `allowAbsoluteUrls` is false');
};
export type UrlPrefixBoundary = {
url?: URL;
prefixUrl?: string;
allowAbsoluteUrls?: boolean;
};
export const getUrlPrefixBoundary = (options: Options): UrlPrefixBoundary => ({
url: options.url instanceof URL ? new URL(options.url) : undefined,
prefixUrl: options.prefixUrl.toString(),
allowAbsoluteUrls: options.allowAbsoluteUrls,
});
export const hasUrlOrPrefixUrlBoundaryChanged = (options: Options, currentUrl: URL, previous: UrlPrefixBoundary): boolean => (
currentUrl.href !== previous.url?.href
|| options.prefixUrl.toString() !== previous.prefixUrl
|| options.allowAbsoluteUrls !== previous.allowAbsoluteUrlsView on GitHub (pinned to e3924aa1e5)
Solutions
- Confirm the intended target origin matches prefixUrl, or set `allowAbsoluteUrls: true` if cross-origin calls are intentional.
- In retry/afterResponse hooks that change origin, use a separate got instance configured for that origin instead of mutating options.url.
- Verify prefixUrl spelling/protocol/host — a stray `http://` vs `https://` or `www.` vs bare domain will trigger this.
Example fix
// before
const client = got.extend({ prefixUrl: 'https://api.example.com' });
hooks: { afterResponse: [(r, retry) => retry({ url: 'https://api.other.com/path' })] }
// after — separate instance for the other origin
const client = got.extend({ prefixUrl: 'https://api.example.com' });
const other = got.extend({ prefixUrl: 'https://api.other.com' });
hooks: { afterResponse: [(r) => r.statusCode === 308 ? other('path') : r] } Defensive patterns
Strategy: validation
Validate before calling
function assertSameOrigin(prefixUrl, targetUrl) {
if (!prefixUrl) return;
const a = new URL(prefixUrl);
const b = targetUrl instanceof URL ? targetUrl : new URL(targetUrl, prefixUrl);
if (a.origin !== b.origin) {
throw new Error(`Cross-origin jump from ${a.origin} to ${b.origin} blocked by allowAbsoluteUrls=false`);
}
}
assertSameOrigin(options.prefixUrl, options.url); Type guard
function isSameOrigin(a: string | URL, b: string | URL): boolean {
const ua = a instanceof URL ? a : new URL(a);
const ub = b instanceof URL ? b : new URL(b);
return ua.origin === ub.origin;
} Try / catch
try {
await client(url, options);
} catch (error) {
if (error instanceof Error && /must stay on the same origin as `prefixUrl`/.test(error.message)) {
// route cross-origin calls through a dedicated instance
const crossOriginClient = got.extend({ prefixUrl: new URL(url).origin, allowAbsoluteUrls: true });
return crossOriginClient(new URL(url).pathname);
}
throw error;
} Prevention
- Keep each got instance scoped to a single origin; use separate instances for other origins.
- In retry/afterResponse hooks that change hosts, build a fresh instance instead of mutating options.url.
- Double-check prefixUrl spelling (protocol, host, www. prefix) — a single character causes origin divergence.
When it happens
Trigger: Calling applyUrlOverride / afterResponse retry with a URL whose origin differs from prefixUrl; prefixUrl set to `https://a.example.com` and a retry/hook switches to `https://b.example.com`; an option merge that changes the resolved URL to a different origin while allowAbsoluteUrls is false.
Common situations: Multi-tenant API clients where a redirect moves between subdomains; SSO flows that hop from app origin to IdP origin; retry hooks that switch to a fallback host; misconfigured prefixUrl with a typo'd host.
Related errors
- The `url` option must be relative when `allowAbsoluteUrls` i
- `url` must not start with a slash
- Missing `url` property
- The `url` option is mutually exclusive with the `input` argu
- `url` protocol must be followed by `//`
AI-assisted analysis of sindresorhus/got@e3924aa1e5 (2026-08-03).
Data as JSON: /data/errors/691de7d78943990b.json.
Report an issue: GitHub.