{"record":{"id":"f0eb2d561b32b0bb","repo":"denoland/deno","slug":"err-http2-invalid-origin","errorCode":"ERR_HTTP2_INVALID_ORIGIN","errorMessage":"HTTP/2 ORIGIN frames require a valid origin","messagePattern":"HTTP/2 ORIGIN frames require a valid origin","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/http2.ts","lineNumber":4656,"sourceCode":"    }\n\n    if (origins.length === 0) {\n      return;\n    }\n\n    let arr = \"\";\n    let len = 0;\n    const count = origins.length;\n    for (let i = 0; i < count; i++) {\n      let origin = origins[i];\n      if (typeof origin === \"string\") {\n        origin = getURLOrigin(origin);\n      } else if (origin != null && typeof origin === \"object\") {\n        origin = origin.origin;\n      }\n      validateString(origin, \"origin\");\n      if (origin === \"null\") {\n        throw new ERR_HTTP2_INVALID_ORIGIN();\n      }\n\n      arr += `${origin}\\0`;\n      len += origin.length;\n    }\n\n    if (len > kMaxALTSVC) {\n      throw new ERR_HTTP2_ORIGIN_LENGTH();\n    }\n\n    this[kHandle].origin(arr, count);\n  }\n}\n\n// ClientHttp2Session instances have to wait for the socket to connect after\n// they have been created. Various operations such as request() may be used,\n// but the actual protocol communication will only occur after the socket\n// has been connected.","sourceCodeStart":4638,"sourceCodeEnd":4674,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/http2.ts#L4638-L4674","documentation":"Http2Session.origin() validates every entry in origins: strings are converted with getURLOrigin(), objects contribute their .origin, and validateString(origin) enforces a string. If the resulting origin is the literal 'null' — the URL parser's opaque-origin marker for schemes like file: or data: — ERR_HTTP2_INVALID_ORIGIN is thrown, since an ORIGIN frame requires concrete serialized origins.","triggerScenarios":"session.origin('file:///srv/site'), session.origin({ origin: 'null' }), or any entry whose URL string has no hierarchical http/https origin.","commonSituations":"Building the origin list from config paths or file:// mounts instead of https:// base URLs; mixing relative paths into the list (those throw ERR_INVALID_URL even earlier via getURLOrigin); opaque origins copied from browser-style URL objects.","solutions":["Pass absolute https:// URLs (ORIGIN frames are only meaningful on TLS) such as 'https://example.com'","Filter the list first: origins.filter((o) => o && o !== 'null') on the string forms","Derive entries from the server's own certificate/hostname configuration, not from request paths"],"exampleFix":"// before\nsession.origin('file:///srv/app', 'https://example.com');\n\n// after\nsession.origin('https://example.com', 'https://cdn.example.com');","handlingStrategy":"validation","validationCode":"const valid = origins.map((o) => typeof o === 'string' ? new URL(o).origin : o?.origin);\nif (valid.some((o) => typeof o !== 'string' || o === 'null')) {\n  throw new TypeError('every origin must be a concrete https origin');\n}\nsession.origin(...origins);","typeGuard":"function areConcreteOrigins(origins) {\n  return origins.every((o) => {\n    const org = typeof o === 'string' ? new URL(o).origin : o?.origin;\n    return typeof org === 'string' && org !== 'null' && org.length > 0;\n  });\n}","tryCatchPattern":null,"preventionTips":["ORIGIN frames are for TLS servers — only https:// origins are meaningful","Filter out 'null'/empty origins before submitting","Non-string, non-null entries fail validateString with ERR_INVALID_ARG_TYPE — normalize first"],"tags":["http2","node-compat","origin-frame","url-parsing"],"backgroundTag":"invalid-url-origin","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}