Skip to content

@appsignal/vue: errorHandler crashes on null instance and cannot resolve component names on Vue 3 #678

Description

@DWonnink

Package: @appsignal/vue 1.1.7
Vue version: 3.5.x

The errorHandler in @appsignal/vue has two problems when used with Vue 3:

1. Crash when Vue invokes the handler with a null instance

Vue 3 calls app.config.errorHandler(err, instance, info) with instance: null for errors outside a component context (e.g. errors in watchers or lifecycle hooks after unmount). The handler dereferences the instance unguarded:

const componentName = vm.$vnode
  ? vm.$vnode.componentOptions.tag // Vue 2
  : vm.$options.name || vm.$options.__name // Vue 3

With vm = null this throws TypeError: Cannot read properties of null (reading '$vnode') inside the error handler itself, so the original error is never reported to AppSignal and never reaches console.error.

2. Component name resolution effectively never works on Vue 3

  • The vm.$vnode branch is Vue 2 API; on Vue 3 it is always undefined, so it is dead code.
  • $options.name is only set for components that declare an explicit name option, which most codebases don't do (the SFC filename is usually the source of truth).
  • $options.__name is only set for <script setup> components.

For classic Options API SFCs without an explicit name, none of the branches match, so every error is reported with the action [unknown Vue component]. In practice this means all frontend errors group under a single incident, which defeats per-component grouping.

Suggested fix

function componentName(vm) {
  const options = vm?.$options
  if (!options) return null
  const file = options.__file?.split("/").pop()?.replace(/\.vue$/, "")
  return options.name || options.__name || file || null
}
  • Optional chaining fixes the null-instance crash.
  • $options.__file is set by vue-loader (always in development; in production when the app opts in via vue-loader's exposeFilename option, which reduces it to the basename). It is a safe extra fallback: absent unless the app opted in, and the [unknown Vue component] fallback is preserved otherwise.

I've opened a PR with this change plus tests alongside this issue.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions