krisk/Fuse · error · Error

Pattern length exceeds max of

Error message

Pattern length exceeds max of ${max}.

What it means

The bitap approximate-matching algorithm encodes the pattern into machine words limited to MAX_BITS (32) characters. A longer pattern makes exact bitap matching impossible, so search throws 'Pattern length exceeds max of 32.' before doing any work.

Solutions

  1. Truncate the query to 32 characters before searching.
  2. Split long input into tokens/words and search each term (or aggregate results).
  3. Enforce a max length on the search input UI and validate before calling search.

Example fix

// before
fuse.search(userInput) // can exceed 32 chars
// after
const pattern = userInput.slice(0, 32)
fuse.search(pattern)
Defensive patterns

Strategy: validation

Validate before calling

const MAX_BITS = 32
let pattern = userInput
if (typeof pattern === 'string' && pattern.length > MAX_BITS) {
  pattern = pattern.slice(0, MAX_BITS)
}
fuse.search(pattern)

Type guard

const isSearchablePattern = (p) => typeof p === 'string' && p.length <= 32

Try / catch

try {
  return fuse.search(query)
} catch (e) {
  if (e.message.startsWith('Pattern length exceeds max')) {
    return fuse.search(query.slice(0, 32))
  }
  throw e
}

Prevention

When it happens

Trigger: Calling bitapSearch/text search (directly or via fuse.search) with a pattern string longer than 32 characters — e.g. a whole sentence, pasted paragraph, or log line used as the query.

Common situations: Unrestricted user search boxes where users paste long text; programmatic queries built by concatenating terms; searching URLs or full lines as the pattern.


AI-assisted analysis of krisk/Fuse@edf2fb608e (2026-09-02). Data as JSON: /api/errors/f048ed233c4a4620. Report an issue: GitHub.

Appendix: source

Thrown at src/search/bitap/search.ts:22

import * as ErrorMsg from '../../core/errorMessages'
import type { SearchResult } from '../../types'

export default function search(
  text: string,
  pattern: string,
  patternAlphabet: Record<string, number>,
  {
    location = Config.location,
    distance = Config.distance,
    threshold = Config.threshold,
    findAllMatches = Config.findAllMatches,
    minMatchCharLength = Config.minMatchCharLength,
    includeMatches = Config.includeMatches,
    ignoreLocation = Config.ignoreLocation
  } = {}
): SearchResult {
  if (pattern.length > MAX_BITS) {
    throw new Error(ErrorMsg.PATTERN_LENGTH_TOO_LARGE(MAX_BITS))
  }

  const patternLen = pattern.length
  // Set starting location at beginning text and initialize the alphabet.
  const textLen = text.length
  // Handle the case when location > text.length
  const expectedLocation = Math.max(0, Math.min(location, textLen))
  // Highest score beyond which we give up.
  let currentThreshold = threshold
  // Is there a nearby exact match? (speedup)
  let bestLocation = expectedLocation

  // Inlined score computation — avoids object allocation per call in hot loops.
  // See ./computeScore.ts for the documented version of this formula.
  const calcScore = (errors: number, currentLocation: number): number => {
    const accuracy = errors / patternLen
    if (ignoreLocation) return accuracy
    const proximity = Math.abs(expectedLocation - currentLocation)

View on GitHub (pinned to edf2fb608e)