vitejs/vite · error · Error

invalid hot.accept() usage.

Error message

invalid hot.accept() usage.

What it means

Vite's HMR client accept() method accepts exactly three valid shapes: no deps / a function (self-accept), a string dep with a callback, or an array of string deps with a callback. If the deps argument is none of these (e.g. a number, an object, or an array containing non-strings), the final else branch throws to signal malformed usage. This protects the HMR dependency graph from invalid registrations.

Source

Thrown at packages/vite/src/shared/hmr.ts:74

    this.newListeners = new Map()
    hmrClient.ctxToListenersMap.set(ownerPath, this.newListeners)
  }

  get data(): any {
    return this.hmrClient.dataMap.get(this.ownerPath)
  }

  accept(deps?: any, callback?: any): void {
    if (typeof deps === 'function' || !deps) {
      // self-accept: hot.accept(() => {})
      this.acceptDeps([this.ownerPath], ([mod]) => deps?.(mod))
    } else if (typeof deps === 'string') {
      // explicit deps
      this.acceptDeps([deps], ([mod]) => callback?.(mod))
    } else if (Array.isArray(deps)) {
      this.acceptDeps(deps, callback)
    } else {
      throw new Error(`invalid hot.accept() usage.`)
    }
  }

  // export names (first arg) are irrelevant on the client side, they're
  // extracted in the server for propagation
  acceptExports(
    _: string | readonly string[],
    callback?: (data: any) => void,
  ): void {
    this.acceptDeps([this.ownerPath], ([mod]) => callback?.(mod))
  }

  dispose(cb: (data: any) => void): void {
    this.hmrClient.disposeMap.set(this.ownerPath, cb)
  }

  prune(cb: (data: any) => void): void {
    this.hmrClient.pruneMap.set(this.ownerPath, cb)

View on GitHub (pinned to 89620f09af)

Solutions

  1. Use one of the documented forms: hot.accept(), hot.accept(() => {}), hot.accept('./dep', cb), or hot.accept(['./a','./b'], cb).
  2. If building deps dynamically, ensure the variable is always undefined, a string, or string[] before calling accept.
  3. Check the browser console for the exact call site and fix the argument type at that location.

Example fix

// before — passing an object
import.meta.hot.accept({ './dep': handler })

// after — pass a string/array with a callback
import.meta.hot.accept(['./dep'], ([dep]) => handler(dep))
Defensive patterns

Strategy: validation

Validate before calling

// Validate the deps argument shape before calling accept
function isValidAcceptDeps(deps: unknown): boolean {
  return (
    deps == null ||
    typeof deps === 'function' ||
    typeof deps === 'string' ||
    (Array.isArray(deps) && deps.every((d) => typeof d === 'string'))
  )
}

if (import.meta.hot && isValidAcceptDeps(myDeps)) {
  import.meta.hot.accept(myDeps as any, cb)
}

Type guard

function isAcceptDeps(deps: unknown): deps is undefined | string | string[] {
  return (
    deps == null ||
    typeof deps === 'string' ||
    (Array.isArray(deps) && deps.every((d) => typeof d === 'string'))
  )
}

Prevention

When it happens

Trigger: Calling import.meta.hot.accept() with a first argument that is not undefined, not a function, not a string, and not an array of strings — for example hot.accept({}), hot.accept(123), or hot.accept([{ foo: 1 }]). Triggered at runtime in the browser/module-runner when the HMR context evaluates the accept call.

Common situations: Dynamically constructing the deps argument to hot.accept and passing a wrong type due to a bug. Misunderstanding the API and passing an object instead of an array. Tooling or codemods that rewrite HMR calls incorrectly. Spread/rest mistakes that pass an object where an array is expected.

Related errors


AI-assisted analysis of vitejs/vite@89620f09af (2026-08-03). Data as JSON: /data/errors/de3f53d34b6f67aa.json. Report an issue: GitHub.