{"record":{"id":"27a72f74d7e78f25","repo":"remix-run/remix","slug":"invalid-hostname-variable","errorCode":null,"errorMessage":"invalid-hostname-variable","messagePattern":"invalid-hostname-variable","errorType":"validation","errorClass":"CreateHrefError","httpStatus":null,"severity":"error","filePath":"packages/route-pattern/src/lib/href.ts","lineNumber":379,"sourceCode":"  return encodePathnameSegment(value).replaceAll('.', '%2E')\n}\n\n/**\n * Keep hostname params from changing URL authority structure when parsed. `@` ends userinfo,\n * `:` starts the port, and `/`, `?`, and `#` start the path, query, and fragment. Hostname\n * variables also reject `.` because dots separate host labels; hostname wildcards allow `.` to\n * span labels intentionally.\n *\n * @see https://url.spec.whatwg.org/#authority-state\n * @see https://url.spec.whatwg.org/#host-parsing\n */\nconst HOSTNAME_PARAM_STRUCTURAL_CHARS = ['@', ':', '/', '?', '#', '%']\n\nexport function validateHostnameVariable(value: unknown): string {\n  let serialized = String(value)\n  for (let char of serialized) {\n    if (char === '.' || isInvalidHostnameParamChar(char)) {\n      throw new CreateHrefError({\n        type: 'invalid-hostname-variable',\n        value: serialized,\n        char,\n      })\n    }\n  }\n  return serialized\n}\n\nexport function validateHostnameWildcard(value: unknown): string {\n  let serialized = String(value)\n  for (let char of serialized) {\n    if (isInvalidHostnameParamChar(char)) {\n      throw new CreateHrefError({\n        type: 'invalid-hostname-wildcard',\n        value: serialized,\n        char,\n      })","sourceCodeStart":361,"sourceCodeEnd":397,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/route-pattern/src/lib/href.ts#L361-L397","documentation":"When substituting a value into a pattern's hostname, the value contained a `.` or a structurally invalid hostname character (@ : / ? # %). These characters cannot appear unescaped in a hostname without breaking URL structure, so href generation fails with invalid-hostname-variable.","triggerScenarios":"Calling href on a pattern with a hostname param (e.g. `:subdomain.example.com`) with a value containing a dot or any of @ : / ? # %, such as 'my.sub' or 'user@host'.","commonSituations":"Treating hostname wildcards/params as free-text; interpolating user-typed input or email addresses into subdomain params; multi-label domains passed where a single label is expected.","solutions":["Pass a single DNS label (no dots) for hostname params","Use a `*` wildcard token if multiple labels must be matched/substituted","Sanitize/validate user input (strip or reject @ : / ? # % and .) before building the href"],"exampleFix":"// before\nhref(parseRoutePattern('https://:tenant.app.com/dashboard'), { tenant: 'acme.eu' })\n\n// after\nhref(parseRoutePattern('https://:tenant.app.com/dashboard'), { tenant: 'acme' })","handlingStrategy":"type-guard","validationCode":"const INVALID = new Set(['@', ':', '/', '?', '#', '%'])\nfunction isValidHostLabel(v: string) { return ![...v].some(c => c === '.' || INVALID.has(c)) }","typeGuard":"function isHostnameLabel(value: unknown): value is string {\n  return typeof value === 'string' && value.length > 0 && ![...value].some(c => c === '.' || '@:/?#%'.includes(c))\n}","tryCatchPattern":null,"preventionTips":["Pass single DNS labels to hostname params","Use wildcards for multi-label hosts","Sanitize user input before interpolating"],"tags":["route-pattern","href","hostname","url"],"backgroundTag":"invalid-hostname-in-url","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}