remix-run/remix · error · CreateHrefError

invalid-pathname-variable

Error message

invalid-pathname-variable

What it means

A pathname variable param was serialized to an empty string. Pathname segments cannot be empty (that would produce a double slash or collapse the path), so href creation fails with invalid-pathname-variable naming the offending param.

Source

Thrown at packages/route-pattern/src/lib/href.ts:338

      return `invalid hostname variable param: ${JSON.stringify(details.value)} contains ${JSON.stringify(details.char)}`
    }

    if (details.type === 'invalid-hostname-wildcard') {
      return `invalid hostname wildcard param: ${JSON.stringify(details.value)} contains ${JSON.stringify(details.char)}`
    }

    if (details.type === 'invalid-pathname-variable') {
      return `invalid pathname variable param: '${details.paramName}' cannot be empty\n\nPattern: ${details.pattern}\nValue: ${JSON.stringify(details.value)}`
    }

    unreachable(details)
  }
}

function encodePathnameVariableParam(pattern: RoutePattern, paramName: string, value: unknown) {
  let serialized = String(value)
  if (serialized.length === 0) {
    throw new CreateHrefError({
      type: 'invalid-pathname-variable',
      pattern,
      paramName,
      value: serialized,
    })
  }
  return encodePathnameVariableSegment(serialized)
}

export function encodePathnameVariable(value: unknown) {
  return encodePathnameVariableSegment(String(value))
}

export function encodePathnameWildcard(value: unknown) {
  return String(value).split('/').map(encodePathnameSegment).join('/')
}

function encodePathnameSegment(value: string): string {

View on GitHub (pinned to 9696913134)

Solutions

  1. Default or guard the param before calling href: skip the link or substitute a placeholder
  2. Allow the segment to be optional in the pattern: `/users(/:id)`
  3. Validate params with a schema (zod etc.) requiring non-empty strings for path params

Example fix

// before
href(userPattern, { id: user.id ?? '' })

// after
href(userPattern, { id: user.id! })
Defensive patterns

Strategy: validation

Validate before calling

for (let [k, v] of Object.entries(params)) {
  if (typeof v === 'string' && v === '') throw new Error(`Param ${k} is empty`)
}

Type guard

function isNonEmptyParam(value: unknown): value is string | number {
  return String(value ?? '').length > 0
}

Try / catch

try { href(pattern, params) } catch (e) { if (e?.type === 'invalid-pathname-variable') { /* default the param */ } }

Prevention

When it happens

Trigger: Calling href with a param whose String(value) is '' for a `:param` used directly as a pathname segment, e.g. pattern `/users/:id` with params { id: '' } or { id: undefined } coerced to 'undefined'-like edge cases where an empty string is explicitly passed.

Common situations: Passing form or URL state that can be empty straight into link builders; trimming user input before validation; defaulting params to '' instead of omitting them; number 0 vs empty string confusion after formatting.

Related errors


AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27). Data as JSON: /api/errors/ffa1c75c97336163. Report an issue: GitHub.