vuejs/vuex · info

[vuex] trying to add a new module '${key}' on hot reloading,

Error message

[vuex] trying to add a new module '${key}' on hot reloading, manual reload is needed

What it means

During hot module replacement, ModuleCollection.update reconciles the old module tree with new definitions. If a new module definition introduces a child that did not exist in the running tree, Vuex cannot hot-swap it and warns that a manual reload is needed, skipping the update.

Source

Thrown at src/module/module-collection.js:96

    return false
  }
}

function update (path, targetModule, newModule) {
  if (__DEV__) {
    assertRawModule(path, newModule)
  }

  // update target module
  targetModule.update(newModule)

  // update nested modules
  if (newModule.modules) {
    for (const key in newModule.modules) {
      if (!targetModule.getChild(key)) {
        if (__DEV__) {
          console.warn(
            `[vuex] trying to add a new module '${key}' on hot reloading, ` +
            'manual reload is needed'
          )
        }
        return
      }
      update(
        path.concat(key),
        targetModule.getChild(key),
        newModule.modules[key]
      )
    }
  }
}

const functionAssert = {
  assert: value => typeof value === 'function',
  expected: 'function'

View on GitHub (pinned to bd907467b8)

Solutions

  1. Perform a full page reload (manual reload) so the store is rebuilt with the new module tree
  2. If the module must appear without reload, call store.registerModule after the hot update instead of relying on HMR
  3. Configure the store HMR handler (module.hot.accept) to recreate or merge modules explicitly
  4. Accept this as expected dev-only behavior; production builds are unaffected

Example fix

// before
if (import.meta.hot) { import.meta.hot.accept(() => { store.hotUpdate(newModules) }) } // newModules adds a brand-new key
// after
if (import.meta.hot) { import.meta.hot.accept(() => { for (const k in newModules) if (!store.hasModule(k)) store.registerModule(k, newModules[k]); store.hotUpdate(newModules) }) }
Defensive patterns

Strategy: fallback

Validate before calling

function diffModules(oldDefs, newDefs, path = []) {
  const added = []
  for (const k in newDefs.modules || {}) {
    const has = oldDefs?.modules && k in oldDefs.modules
    if (!has) added.push([...path, k].join('/'))
    added.push(...diffModules(oldDefs?.modules?.[k], newDefs.modules[k], [...path, k]))
  }
  return added
}
// if diffModules(old, new).length, do a full store rebuild instead of hotUpdate

Type guard

function canHotUpdate(oldModule, key) {
  return Boolean(oldModule && oldModule.getChild && oldModule.getChild(key))
}

Try / catch

if (import.meta.hot) {
  import.meta.hot.accept(() => {
    try { store.hotUpdate(newModules) }
    catch (e) { console.warn('hot update incomplete, reloading', e); location.reload() }
  })
}

Prevention

When it happens

Trigger: Editing store modules with HMR active and adding a brand-new key under modules (e.g. adding modules: { reports } to a store that previously had no 'reports'); hot reload after code-splitting introduces a new nested module.

Common situations: webpack/vite HMR during development of Vuex modules; adding a feature module to an existing namespaced parent; new nested route module added while dev server is running.

Related errors


AI-assisted analysis of vuejs/vuex@bd907467b8 (2026-08-28). Data as JSON: /api/errors/81232c78bdba5fc8. Report an issue: GitHub.