skip to content

In Vue 3, what does app.config.warnHandler receive, how does it differ from app.config.errorHandler, and why is it not a production hook?

level: middleimportance: should knowfreq 45%

answer

  1. message, instance, trace
  2. replaces console output
  3. warnings are dev-only
  4. errors in both modes
  5. info shortened in production

basics

~10 s

warnHandler(msg, instance, trace) intercepts Vue's development warnings, which do not exist in production builds. errorHandler(err, instance, info) receives uncaught runtime errors in both development and production, so only errorHandler belongs in production reporting.

solid answer

~40 s

`app.config.warnHandler` is called with the warning message, the component instance that caused it and a component trace. Setting it replaces Vue's own `console.warn` output, which is useful for filtering noise during a debugging session. Vue's warnings are compiled out of production builds, so the handler is never called there. `app.config.errorHandler` is different: it receives `(err, instance, info)` for errors that escape component code, from renders, event handlers, lifecycle hooks, `setup`, watchers, custom directive hooks and transition hooks, in development and production alike. In production `info` is a link to Vue's error-code reference rather than the readable description. So `errorHandler` is where production error reporting goes; `warnHandler` is a debugging aid.

code

ts · 20 lines
ts
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

app.config.errorHandler = (err, instance, info) => {
  // production and development: report, then keep the app alive
  reportError({ err, info, component: instance?.$options.name })
}

if (import.meta.env.DEV) {
  app.config.warnHandler = (msg, instance, trace) => {
    if (msg.includes('Extraneous non-props attributes')) return // debugging only
    console.warn(`[Vue warn]: ${msg}\n${trace}`)
  }
}

app.mount('#app')

declare function reportError(payload: object): void

go deeper

for a junior

Recall the two handler names, their three arguments, and that warnings exist only in development.

for a middle

Explain which sources errorHandler catches, the dev-rethrow versus prod-log default, and why warnHandler replaces console output.

for a senior

Design production reporting on errorHandler with production info codes in mind, and use warnHandler only to harden development and tests.

for a principal

Decide how warnings and errors feed quality gates: warnings failing CI in development builds, errors routed to monitoring with ownership per app.

## Two hooks, two purposes Both handlers live on the application's `config` object, set on the app returned by `createApp()` and applying to every component in that app. They look similar but answer different questions. | | `app.config.warnHandler` | `app.config.errorHandler` | |---|---|---| | Receives | `(msg, instance, trace)` | `(err, instance, info)` | | Triggered by | Vue's own development warnings | errors thrown by application code that Vue calls | | Development | called instead of printing to the console | called; without it, Vue rethrows | | Production | never called, warnings are compiled out | called; without it, Vue logs to the console | | Typical use | filter warnings while debugging | report errors to monitoring, show a fallback | ## warnHandler in detail A **warning** is Vue telling a developer about probable misuse: an unknown component, a missing required prop, an extraneous non-prop attribute on a fragment root, a failed mount selector. In development Vue normally prints each one with a `[Vue warn]` prefix and a component trace. When `warnHandler` is set: - Vue calls it with the message, the public instance of the component that was active (or `null`) and the trace formatted as lines like `at <UserCard>`; - Vue no longer prints the warning itself, so the handler fully owns the output. That makes it handy for a focused debugging session: suppress one noisy warning category and log the rest. The docs recommend removing it once debugging is done, because every warning points at something that should be fixed. In production builds the warning calls are removed at compile time, so the handler is never invoked; it cannot be used for production telemetry. ## errorHandler in detail Vue wraps the user code it calls: component render functions, `setup()`, lifecycle hooks, event handlers, watcher getters and callbacks, custom directive hooks and transition hooks. When one of these throws, and nothing closer to the component has handled it, Vue calls `errorHandler` with: 1. `err`, the thrown value; 2. `instance`, the public instance of the component where it happened, or `null`; 3. `info`, a string naming the source, such as `render function`, `setup function` or `watcher callback` in development. In production builds `info` is shortened: Vue passes a link to its production error-code reference, ending in a code, instead of the readable name, so the reporting code should record it verbatim. The default when no handler exists is to **rethrow in development** and **log with `console.error` in production**; version 3.5 added an option to make production rethrow too. How errors travel to this handler through component-level error hooks is a separate topic; for configuration purposes, `errorHandler` is the app's last stop. ## Choosing between them - Production monitoring: `errorHandler` is the direct route; Vue 3.5 also offers rethrowing unhandled errors to page-level listeners instead. - Silencing a warning in CI logs: fix the cause; only as a temporary measure filter it with `warnHandler`. - Failing tests on any Vue warning: a `warnHandler` that throws is a common trick in development-mode test runs, since tests run with warnings enabled. ## Wiring them in a real project 1. Set `errorHandler` unconditionally in the app's entry file, so development and production share one reporting path. 2. Include `info` and, where available, the component name from `instance` in every report; in production, store the reference link as-is and look it up when triaging. 3. Keep the handler defensive: it runs while the app is already in an error state, so it should never throw. 4. Guard any `warnHandler` behind a development check, even though production would never call it, so its purpose is obvious to readers. 5. Remove temporary warning filters when the debugging session ends; a permanently filtered warning is a permanently hidden bug. ## Common mistakes - Setting `warnHandler` in production and expecting warnings to arrive. - Treating a warning as an error: warnings never interrupt execution. - Expecting the `info` string to read the same in production as in development. - Forgetting that a throwing `errorHandler` is itself caught and logged by Vue rather than rethrown into the component.

  • What happens if app.config.errorHandler itself throws?
    Vue calls the handler through its own error-handling wrapper with no component instance, so an exception thrown inside it is not sent back into the handler. It is treated as an unhandled error: logged, and rethrown in development. Keep the handler defensive, for example wrapping the reporting call in try/catch.
  • Why can a warnHandler that throws be useful in a test suite?
    Tests usually run with development builds, where warnings exist. A `warnHandler` that throws turns every Vue warning, such as a missing required prop, into a test failure, so misuse cannot slip through as console noise.

saying these in an interview costs you the question

  • warnHandler is a good place to send production telemetry
  • Setting warnHandler still prints each warning to the console as well
  • errorHandler only runs in development builds
  • A Vue warning stops the component from rendering
  • The info argument is the same readable text in production