remix-run/remix · error · CreateHrefError
invalid-hostname-variable
Error message
invalid-hostname-variable
What it means
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.
Source
Thrown at packages/route-pattern/src/lib/href.ts:379
return encodePathnameSegment(value).replaceAll('.', '%2E')
}
/**
* Keep hostname params from changing URL authority structure when parsed. `@` ends userinfo,
* `:` starts the port, and `/`, `?`, and `#` start the path, query, and fragment. Hostname
* variables also reject `.` because dots separate host labels; hostname wildcards allow `.` to
* span labels intentionally.
*
* @see https://url.spec.whatwg.org/#authority-state
* @see https://url.spec.whatwg.org/#host-parsing
*/
const HOSTNAME_PARAM_STRUCTURAL_CHARS = ['@', ':', '/', '?', '#', '%']
export function validateHostnameVariable(value: unknown): string {
let serialized = String(value)
for (let char of serialized) {
if (char === '.' || isInvalidHostnameParamChar(char)) {
throw new CreateHrefError({
type: 'invalid-hostname-variable',
value: serialized,
char,
})
}
}
return serialized
}
export function validateHostnameWildcard(value: unknown): string {
let serialized = String(value)
for (let char of serialized) {
if (isInvalidHostnameParamChar(char)) {
throw new CreateHrefError({
type: 'invalid-hostname-wildcard',
value: serialized,
char,
})View on GitHub (pinned to 9696913134)
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
Example fix
// before
href(parseRoutePattern('https://:tenant.app.com/dashboard'), { tenant: 'acme.eu' })
// after
href(parseRoutePattern('https://:tenant.app.com/dashboard'), { tenant: 'acme' }) Defensive patterns
Strategy: type-guard
Validate before calling
const INVALID = new Set(['@', ':', '/', '?', '#', '%'])
function isValidHostLabel(v: string) { return ![...v].some(c => c === '.' || INVALID.has(c)) } Type guard
function isHostnameLabel(value: unknown): value is string {
return typeof value === 'string' && value.length > 0 && ![...value].some(c => c === '.' || '@:/?#%'.includes(c))
} Prevention
- Pass single DNS labels to hostname params
- Use wildcards for multi-label hosts
- Sanitize user input before interpolating
When it happens
Trigger: 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'.
Common situations: 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.
Related errors
AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27).
Data as JSON: /api/errors/27a72f74d7e78f25.
Report an issue: GitHub.