angular/angular · error · RuntimeError
INVALID_URL
INVALID_URL
Error message
Invalid URL: ${urlStr} What it means
resolveUrl() in platform-server first tries `new URL(urlStr)`; if that fails it checks `URL.canParse(urlStr, 'http://fake')` to detect inputs that carry a scheme (e.g. `http:`) but are malformed absolute URLs, such as a double port `http://host:8080:9090/`. Per the WHATWG spec such input parses strictly against the base and still fails, so the flow throws INVALID_URL rather than silently resolving a broken absolute URL against the app origin.
Source
Thrown at packages/platform-server/src/url.ts:83
resolved = new URL(urlStr);
} catch {}
const {allowProtocolRelative = false, allowOriginChange = true} = options;
if (resolved) {
if (originUrl && !isSafeOriginChange(resolved, originUrl, urlStr, allowOriginChange)) {
throwSuspiciousUrlError(urlStr);
}
return resolved;
}
// We identify and throw on malformed absolute URLs (like double port).
// Per the WHATWG URL standard, parsing an input starting with a scheme (like 'http:') against
// a standard base (like 'http://fake') ignores the base argument and parses strictly as an
// absolute URL. Since it is malformed, the native URL constructor will throw a validation
// error. Standard relative/protocol-relative paths parse successfully, allowing the flow to continue.
if (!URL.canParse(urlStr, 'http://fake')) {
throw new RuntimeError(
RuntimeErrorCode.INVALID_URL,
typeof ngDevMode === 'undefined' || ngDevMode ? `Invalid URL: ${urlStr}` : urlStr,
);
}
if (!originUrl) {
return null;
}
// Check if we have a legitimate protocol-relative URL (starts with '//' and not a duplicate/backslash bypass)
// and we are configured to allow and preserve standard cross-origin protocol-relative requests.
if (urlStr.startsWith('//')) {
if (!allowProtocolRelative) {
throw new RuntimeError(
RuntimeErrorCode.PROTOCOL_RELATIVE_URL_NOT_ALLOWED,
typeof ngDevMode === 'undefined' || ngDevMode
? `Protocol relative URLs are not allowed in this context. URL: ${urlStr}`
: urlStr,View on GitHub (pinned to 51cb07e980)
Solutions
- Fix the URL string itself — remove the duplicate port/whitespace/invalid characters (the message prints the exact offending URL)
- Validate with `URL.canParse(url)` (or try `new URL(url)`) before passing the URL into renderApplication/INITIAL_CONFIG
- Check proxy header handling (Host, X-Forwarded-Host, X-Forwarded-Port) that builds the URL server-side
Example fix
// before
const url = `${protocol}//${host}:${port}:${altPort}/app`; // double port
await renderApplication(bootstrap, {url}); // Invalid URL
// after
const url = `${protocol}//${host}:${port}/app`;
if (!URL.canParse(url)) throw new Error(`Bad request URL: ${url}`);
await renderApplication(bootstrap, {url}); Defensive patterns
Strategy: validation
Validate before calling
// Validate before passing to renderApplication / INITIAL_CONFIG
function isParseableAbsoluteUrl(url: string): boolean {
return URL.canParse(url);
}
if (!isParseableAbsoluteUrl(requestUrl)) {
throw new Error(`Refusing to render: malformed request URL ${JSON.stringify(requestUrl)}`);
} Try / catch
try {
await renderApplication(bootstrap, {url});
} catch (e) {
if (e instanceof Error && e.message.startsWith('Invalid URL:')) {
// log the offending URL and reject the request with 400
respond400(`Malformed request URL: ${url}`);
} else {
throw e;
}
} Prevention
- Never assemble absolute URLs by string concatenation of proxy headers; use new URL() to build them
- Validate inbound request URLs with URL.canParse at the server request handler boundary
- Log the exact failing URL (the error message embeds it) before discarding the error
When it happens
Trigger: Passing a scheme-bearing malformed URL to any resolveUrl consumer: the `url` option of renderApplication/renderModule, INITIAL_CONFIG `{url: ...}` for ServerPlatformLocation, or the platform-server relative-URL interceptor receiving e.g. `http://host:8080:8080/path`, `https://exa mple.com`, or `https://[bad`.
Common situations: Reverse proxies forwarding malformed Host or X-Forwarded-Host headers that produce double-port URLs; environment variables or config files supplying a malformed absolute URL; string concatenation bugs when assembling request URLs on the server.
Related errors
- HTTP_ORIGIN_MAP_CONTAINS_PATH
- Invalid URL (${url}) with base (${base})
- PROTOCOL_RELATIVE_URL_NOT_ALLOWED
- SUSPICIOUS_URL_CHANGE_ORIGIN
- INVALID_TIMEOUT_VALUE
AI-assisted analysis of angular/angular@51cb07e980 (2026-08-22).
Data as JSON: /api/errors/903c0dafa2278553.
Report an issue: GitHub.