remix-run/remix · error · ParseError

invalid protocol

Error message

invalid protocol

What it means

Thrown by parseProtocol when parsing a route pattern whose protocol segment is not one of the supported values. Remix route patterns only allow 'http', 'https', or 'http(s)' before the '://' separator; anything else is rejected. The error is a ParseError that includes the source position of the offending protocol.

Source

Thrown at packages/route-pattern/src/lib/route-pattern/parse.ts:258

    if (token.type === ':' || token.type === '*') {
      structure += token.type
      captures += `${token.type}:${token.name}|`
    } else if (token.type === 'text') {
      structure += `t:${token.text}|`
    } else {
      structure += `${token.type}|`
    }
  }
  return { structure, captures }
}

function parseProtocol(source: string, span: Span | null): RoutePatternParts['protocol'] {
  if (!span) return null
  let protocol = source.slice(...span)
  if (protocol === '' || protocol === 'http' || protocol === 'https' || protocol === 'http(s)') {
    return protocol === '' ? null : protocol
  }
  throw new ParseError('invalid protocol', source, span[0])
}

function parseHostname(source: string, span: Span | null): RoutePatternParts['hostname'] | null {
  if (!span) return null
  let part = parsePart(source, { span, type: 'hostname' })
  if (isNamelessWildcard(part)) return null
  return part
}

function isNamelessWildcard(part: PartPattern): boolean {
  if (part.tokens.length !== 1) return false
  let token = part.tokens[0]
  if (token.type !== '*') return false
  return token.name === '*'
}

function parseSearch(source: string): RoutePatternParts['search'] {
  let constraints = new Map<string, Set<string>>()

View on GitHub (pinned to 9696913134)

Solutions

  1. Change the protocol segment to 'http', 'https', or 'http(s)'
  2. Remove the protocol segment entirely if you don't need protocol matching
  3. Check for typos or stray characters before the '://' in the pattern

Example fix

// before
parsePattern('ftp://example.com/files/*')
// after
parsePattern('http(s)://example.com/files/*')
Defensive patterns

Strategy: validation

Validate before calling

let PROTOCOLS = new Set(['http', 'https', 'http(s)'])
function hasValidProtocol(pattern: string): boolean {
  let m = /^([a-z]+\(s\)|[a-z]+):\/\//.exec(pattern)
  return m == null || PROTOCOLS.has(m[1])
}

Type guard

function isSupportedProtocol(protocol: string): protocol is 'http' | 'https' | 'http(s)' {
  return protocol === 'http' || protocol === 'https' || protocol === 'http(s)'
}

Try / catch

try { parsePattern(pattern) } catch (e) { if (e instanceof ParseError) return fallbackRoute(e) ; throw e }

Prevention

When it happens

Trigger: Calling parsePattern (directly or via route configuration) with a pattern like 'ftp://host/path' or 'ws://host/path', or any protocol segment other than '', 'http', 'https', 'http(s)'.

Common situations: Copying a URL with an unsupported scheme (ftp:, ws:, wss:) into a route pattern; typos like 'httpx://' or trailing whitespace in the protocol segment; assuming any URL scheme is a valid pattern prefix.

Related errors


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