honojs/hono · error · TypeError

Invalid rule: ${rule}

Error message

Invalid rule: ${rule}

What it means

This TypeError is thrown by the ip-restriction middleware's CIDR parsing when a rule string's prefix (the part after '/') is not 1-3 digits or exceeds the maximum prefix length for the address family (32 for IPv4, 128 for IPv6). Rules are parsed eagerly when the middleware is created, so bad rules fail fast with 'Invalid rule: <rule>'.

Source

Thrown at src/middleware/ip-restriction/index.ts:43

/**
 * ### IPv4 and IPv6
 * - `*` match all
 *
 * ### IPv4
 * - `192.168.2.0` static
 * - `192.168.2.0/24` CIDR Notation
 *
 * ### IPv6
 * - `::1` static
 * - `::1/10` CIDR Notation
 */
type IPRestrictionRuleFunction = (addr: { addr: string; type: AddressType }) => boolean
export type IPRestrictionRule = string | ((addr: { addr: string; type: AddressType }) => boolean)

const IS_CIDR_NOTATION_REGEX = /\/[^/]*$/
const parseCidrPrefix = (rule: string, prefix: string, max: number): number => {
  if (!/^[0-9]{1,3}$/.test(prefix)) {
    throw new TypeError(`Invalid rule: ${rule}`)
  }
  const parsedPrefix = parseInt(prefix)
  if (parsedPrefix > max) {
    throw new TypeError(`Invalid rule: ${rule}`)
  }
  return parsedPrefix
}
const buildMatcher = (
  rules: IPRestrictionRule[]
): ((addr: { addr: string; type: AddressType; isIPv4: boolean }) => boolean) => {
  const functionRules: IPRestrictionRuleFunction[] = []
  const staticRules: Set<string> = new Set()
  const staticIPv4Rules: Set<bigint> = new Set()
  const staticIPv6Rules: Set<bigint> = new Set()
  const cidrRules: [boolean, bigint, bigint][] = []
  const registerStaticRule = (rule: string): void => {
    const type = distinctRemoteAddr(rule)
    if (type === undefined) {

View on GitHub (pinned to e2740d5a1b)

Solutions

  1. Correct the rule to valid CIDR: digits only after the slash, within 0-32 (IPv4) or 0-128 (IPv6)
  2. If rules come from config/env, validate them at startup (regex + range check) before creating the middleware
  3. Use the function form of a rule — (addr) => boolean — for non-CIDR logic instead of malformed strings
  4. Test rule lists in CI so a typo fails the build, not deployment

Example fix

// before
const restriction = ipRestriction(['10.0.0.0/8x', '192.168.1.0/24'])

// after
const restriction = ipRestriction(['10.0.0.0/8', '192.168.1.0/24'])
Defensive patterns

Strategy: validation

Validate before calling

const isValidCidrRule = (rule: string): boolean => {
  const m = rule.match(/^(\d{1,3}(?:\.\d{1,3}){3}|[0-9a-fA-F:]+)\/(\d{1,3})$/)
  if (!m) return false
  const max = rule.includes(':') ? 128 : 32
  return Number(m[2]) <= max
}

const rules = (process.env.ALLOWED_CIDRS ?? '').split(',').map((s) => s.trim()).filter(Boolean)
if (!rules.every(isValidCidrRule)) throw new Error('Invalid CIDR in ALLOWED_CIDRS')
const mw = ipRestriction(rules)

Type guard

const isCidrRule = (r: string): boolean => {
  const idx = r.lastIndexOf('/')
  if (idx === -1) return true // plain IP
  const prefix = r.slice(idx + 1)
  const max = r.includes(':') ? 128 : 32
  return /^[0-9]{1,3}$/.test(prefix) && parseInt(prefix) <= max
}

Try / catch

null

Prevention

When it happens

Trigger: Passing rules like '10.0.0.0/8x' (non-numeric prefix), '10.0.0.0/' or '10.0.0.0/abc' (fails the digits regex), '10.0.0.0/33' (>32 for IPv4), '::1/129' (>128 for IPv6); building rules from user input or env vars without validation; joining rules with extra slashes.

Common situations: Env-configured allowlists with typos, generating CIDR ranges programmatically and emitting an empty or invalid prefix, confusing subnet mask notation (255.255.0.0) with CIDR prefix length (/16), or IPv6 rules written with an embedded '/' mistake.

Related errors


AI-assisted analysis of honojs/hono@e2740d5a1b (2026-08-28). Data as JSON: /api/errors/2600f0f19787391d. Report an issue: GitHub.