{"record":{"id":"8fc1e5702654b114","repo":"denoland/deno","slug":"err-invalid-url-8fc1e5","errorCode":"ERR_INVALID_URL","errorMessage":"Invalid URL: ${urlStr}","messagePattern":"Invalid URL: (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/http2.ts","lineNumber":307,"sourceCode":"}\n\nfunction debugSession(sessionType, message, ...args) {\n  ReflectApply(debug, null, [\n    \"Http2Session %s: \" + message,\n    sessionName(sessionType),\n    ...new SafeArrayIterator(args),\n  ]);\n}\n\nfunction debugSessionObj(session, message, ...args) {\n  debugSession(session[kType], message, ...new SafeArrayIterator(args));\n}\n\nfunction getURLOrigin(urlStr) {\n  try {\n    return new URL(urlStr).origin;\n  } catch {\n    throw new ERR_INVALID_URL(urlStr);\n  }\n}\n\nfunction perfNow() {\n  return webPerformance.now();\n}\n\nfunction emitSessionPerfEntry(session) {\n  if (session[kPerfEmitted]) return;\n  session[kPerfEmitted] = true;\n  const stats = session[kPerfStats];\n  if (!stats) return;\n\n  const startTime = stats.startTime;\n  const duration = perfNow() - startTime;\n  const handle = session[kHandle];\n  const framesReceived = handle && typeof handle.framesReceived === \"function\"\n    ? handle.framesReceived()","sourceCodeStart":289,"sourceCodeEnd":325,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/http2.ts#L289-L325","documentation":"getURLOrigin parses a string with new URL(urlStr) and takes .origin; any parse failure is rethrown as ERR_INVALID_URL. It is used when submitting ORIGIN frames (http2session.origin(...origins)), alt-svc frames (http2session.altsvc(alt, origin)), and when computing session.originSet, so HTTP/2 metadata frames never carry a malformed origin.","triggerScenarios":"session.origin('example.com') (no scheme); session.altsvc('h2=\":8443\"', 'https://') (empty host); origins built by concatenation that yield strings with spaces or invalid characters; passing a URL string that is not absolute (no protocol).","commonSituations":"Config files that store bare hostnames and are fed to session.origin/altsvc without normalization; building origins from user input via template strings; non-ASCII or unserialized punycode hostnames; porting code that assumed lenient parsing.","solutions":["Pass full absolute URLs with scheme and host: session.origin('https://example.com:8443')","Pass URL objects instead of strings — the implementation uses their .origin property and skips parsing","Pre-validate with new URL(str) (or URL.canParse(str)) before calling origin() or altsvc()"],"exampleFix":"// before\nsession.origin('example.com'); // throws ERR_INVALID_URL\n\n// after\nsession.origin(new URL('https://example.com')); // uses .origin, no parse risk","handlingStrategy":"validation","validationCode":"const parseableOrigin = (s: string): boolean => {\n  try {\n    return new URL(s).origin !== 'null';\n  } catch {\n    return false;\n  }\n};\nif (!parseableOrigin(originStr)) throw new Error(`bad origin: ${originStr}`);\nsession.origin(originStr);","typeGuard":"const isAbsoluteHttpUrl = (v: string): boolean =>\n  URL.canParse(v) && /^https?:$/.test(new URL(v).protocol);","tryCatchPattern":"try {\n  session.origin(originStr);\n} catch (err) {\n  if ((err as NodeJS.ErrnoException).code === 'ERR_INVALID_URL') {\n    // drop or fix the malformed origin, then continue\n  } else throw err;\n}","preventionTips":["Pass URL objects to session.origin/altsvc so parsing happens once, up front","Store full absolute origins (scheme + host + port) in config, not bare hostnames","Normalize with new URL(...).origin at config-load time"],"tags":["http2","url-parsing","node-compat","origin-frame"],"backgroundTag":"invalid-url","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}