Skip to content

Commit c7f2b8b

Browse files
committed
fix: avoid recursive error handling
1 parent 9e88707 commit c7f2b8b

File tree

2 files changed

+37
-0
lines changed

2 files changed

+37
-0
lines changed

src/core/util/error.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { inBrowser } from './env'
44
import { isPromise } from 'shared/util'
55
import { pushTarget, popTarget } from '../observer/dep'
66

7+
let isHandlingError = false
8+
79
export function handleError(err: Error, vm: any, info: string) {
810
// Deactivate deps tracking while processing error handler to avoid possible infinite rendering.
911
// See: https://github.com/vuejs/vuex/issues/1505
@@ -55,14 +57,21 @@ export function invokeWithErrorHandling(
5557

5658
function globalHandleError(err, vm, info) {
5759
if (config.errorHandler) {
60+
if (isHandlingError) {
61+
logError(err, vm, info)
62+
return
63+
}
5864
try {
65+
isHandlingError = true
5966
return config.errorHandler.call(null, err, vm, info)
6067
} catch (e: any) {
6168
// if the user intentionally throws the original error in the handler,
6269
// do not log it twice
6370
if (e !== err) {
6471
logError(e, null, 'config.errorHandler')
6572
}
73+
} finally {
74+
isHandlingError = false
6675
}
6776
}
6877
logError(err, vm, info)

test/unit/features/error-handling.spec.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,34 @@ describe('Error handling', () => {
216216
Vue.config.errorHandler = undefined
217217
})
218218

219+
it('should avoid recursive error handling when errorHandler triggers another error', () => {
220+
const originalHandler = Vue.config.errorHandler
221+
let handlerCalls = 0
222+
Vue.config.errorHandler = (err, instance) => {
223+
handlerCalls++
224+
if (handlerCalls === 1 && instance) {
225+
instance.$emit('boom')
226+
}
227+
}
228+
new Vue({
229+
created() {
230+
this.$on('boom', () => {
231+
throw new Error('error in boom')
232+
})
233+
},
234+
render(h) {
235+
throw new Error('error in render')
236+
},
237+
renderError(h, err) {
238+
return h('div', err.toString())
239+
}
240+
}).$mount()
241+
expect(handlerCalls).toBe(1)
242+
expect('Error in event handler for "boom"').toHaveBeenWarned()
243+
expect('Error: error in boom').toHaveBeenWarned()
244+
Vue.config.errorHandler = originalHandler
245+
})
246+
219247
// event handlers that can throw errors or return rejected promise
220248
;[
221249
['single handler', '<div v-on:click="bork"></div>'],

0 commit comments

Comments
 (0)