honojs/hono · error · Error

Middleware vary configuration cannot include "*", as it disa

Error message

Middleware vary configuration cannot include "*", as it disallows effective caching.

What it means

This error is thrown by Hono's cache() middleware when the vary configuration contains the wildcard '*'. RFC 7231 Section 7.1.4 disallows '*' in the Vary header because it tells caches the response varies by unspecified request aspects, making effective caching impossible. The middleware validates directives up front and fails fast at configuration time rather than emitting an invalid header at runtime.

Source

Thrown at src/middleware/cache/index.ts:220

    reportCacheNotAvailable(
      options.onCacheNotAvailable,
      'Cache Middleware cannot cache QUERY requests because Web Crypto is not available.'
    )
  }

  if (options.wait === undefined) {
    options.wait = false
  }

  const cacheControlDirectives = options.cacheControl
    ?.split(',')
    .map((directive) => directive.toLowerCase())
  const optionsVaryList = parseVaryDirectives(options.vary)
  const varyDirectives = optionsVaryList.length ? new Set(optionsVaryList) : undefined
  // RFC 7231 Section 7.1.4 specifies that "*" is not allowed in Vary header.
  // See: https://datatracker.ietf.org/doc/html/rfc7231#section-7.1.4
  if (varyDirectives?.has('*')) {
    throw new Error(
      'Middleware vary configuration cannot include "*", as it disallows effective caching.'
    )
  }

  const cacheableStatusCodes = new Set<number>(
    options.cacheableStatusCodes ?? defaultCacheableStatusCodes
  )
  const maxQueryBodySize = options.maxQueryBodySize ?? defaultMaxQueryBodySize

  const addHeader = (c: Context, responseVary: string[]) => {
    if (cacheControlDirectives) {
      const existingDirectives =
        c.res.headers
          .get('Cache-Control')
          ?.split(',')
          // Directive names are case-insensitive (RFC 7234 §5.2); lower-case so
          // the case-insensitive de-dup check below matches handler-set names
          // like `Max-Age`.

View on GitHub (pinned to e2740d5a1b)

Solutions

  1. Replace '*' with the concrete request headers the response actually depends on
  2. If vary comes from external input, filter out '*' (case-insensitive) before passing it
  3. Use the array form for clarity: vary: ['Accept-Encoding', 'Accept-Language']
  4. If you truly cannot enumerate the varying headers, omit vary entirely instead of using '*'

Example fix

// before
app.get('/data', cache({ cacheName: 'my-cache', vary: '*' }))

// after
app.get('/data', cache({ cacheName: 'my-cache', vary: ['Accept-Encoding', 'Accept-Language'] }))
Defensive patterns

Strategy: validation

Validate before calling

const sanitizeVary = (vary: string[]): string[] =>
  vary.map((d) => d.trim().toLowerCase()).filter((d) => d !== '*')

const mw = cache({ cacheName: 'x', vary: sanitizeVary(userVary) })

Type guard

const isValidVary = (vary: string[]): boolean =>
  vary.every((d) => /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(d) && d !== '*')

Prevention

When it happens

Trigger: Calling cache({ cacheName: 'x', vary: '*' }); building vary from user input that may contain '*'; splitting a comma string like '*, Accept-Encoding' and passing the array; copying a Vary header value from an upstream service into options.vary without filtering.

Common situations: Passing a raw header value collected from another response into vary, dynamic vary lists where '*' sneaks in, misunderstanding that the option takes concrete header names only (e.g. 'Accept-Encoding', 'Accept-Language').

Related errors


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