{"record":{"id":"4d873baa0873133d","repo":"nodejs/node","slug":"invalid-url-url","errorCode":null,"errorMessage":"Invalid URL: ${url}","messagePattern":"Invalid URL: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"deps/npm/lib/utils/open-url.js","lineNumber":13,"sourceCode":"const { open } = require('@npmcli/promise-spawn')\nconst { output, input, META } = require('proc-log')\nconst { URL } = require('node:url')\nconst readline = require('node:readline/promises')\nconst { once } = require('node:events')\n\nconst assertValidUrl = (url) => {\n  try {\n    if (!/^https?:$/.test(new URL(url).protocol)) {\n      throw new Error()\n    }\n  } catch {\n    throw new Error('Invalid URL: ' + url)\n  }\n}\n\nconst outputMsg = (json, title, url) => {\n  if (json) {\n    output.buffer({ title, url })\n  } else {\n    // These urls are sometimes specifically login urls so we have to turn off redaction to standard output\n    output.standard(`${title}:\\n${url}`, { [META]: true, redact: false })\n  }\n}\n\n// attempt to open URL in web-browser, print address otherwise:\nconst openUrl = async (npm, url, title, isFile) => {\n  url = encodeURI(url)\n  const browser = npm.config.get('browser')\n  const json = npm.config.get('json')\n","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/npm/lib/utils/open-url.js#L1-L31","documentation":"Thrown by assertValidUrl in open-url.js when the URL either fails to parse via the URL constructor or parses but has a protocol other than `http:` or `https:`. The helper is used by openUrl (unless isFile is true, as for help pages) and by openUrlPrompt before showing a login URL. It guards against `file:`, `javascript:`, or malformed strings being handed to the browser opener.","triggerScenarios":"An npm command (e.g. login, docs, repo, author) computes a URL that is non-HTTP, or a custom config value (homepage, repository, docs) resolves to something unparsable or to a `file:`/`git:` URL. Also if a registry or auth opener returns a malformed URL.","commonSituations":"package.json `homepage` set to a `git@host:` SSH string or a relative path; a plugin/proxy that returns a non-absolute login URL; typos like 'htp://'; an internal registry whose web UI config field is empty.","solutions":["Ensure the relevant metadata/config (homepage, repository.url, docs) is a fully-qualified `https://` URL.","If hitting this during `npm login`, verify the registry's web base URL is reachable and absolute.","For local help/file URLs, note the openUrl `isFile` path skips this check; use the help flow rather than a custom URL."],"exampleFix":"// before\n// package.json: \"homepage\": \"git@github.com:owner/repo\"\nnpm repo\n// after\n// package.json: \"homepage\": \"https://github.com/owner/repo\"\nnpm repo","handlingStrategy":"validation","validationCode":"const assertHttpUrl = (url) => {\n  let u\n  try { u = new URL(url) } catch { throw new Error(`Invalid URL: ${url}`) }\n  if (!/^https?:$/.test(u.protocol)) throw new Error(`Invalid URL: ${url}`)\n}","typeGuard":"const isHttpUrl = (v) => {\n  try { return /^https?:$/.test(new URL(v).protocol) } catch { return false }\n}","tryCatchPattern":"try {\n  await openUrl(npm, url, title, isFile)\n} catch (err) {\n  if (/^Invalid URL:/i.test(err.message)) {\n    // log the offending URL source field (homepage/repository) for the user to fix\n  } else { throw err }\n}","preventionTips":["Use full https:// URLs in all package.json metadata fields (homepage, repository.url, docs).","Avoid SSH (`git@host:`) or relative URLs where a browser URL is expected.","Sanitize/validate URLs in tooling before passing them to npm's opener."],"tags":["validation","url","security","browser","config"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}