Skip to content

Commit 2933cf3

Browse files
EbonsignoriCopilot
andauthored
[Sentry Auto-Fix] DOCS-2J9: TypeError: terminated (#59287)
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: Ebonsignori <17055832+Ebonsignori@users.noreply.github.com>
1 parent 35776fb commit 2933cf3

File tree

3 files changed

+89
-20
lines changed

3 files changed

+89
-20
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
export type ErrorWithCode = Error & {
2+
code: string
3+
statusCode?: number
4+
status?: string
5+
}
6+
7+
export function shouldLogException(error: ErrorWithCode) {
8+
const IGNORED_ERRORS = [
9+
// Client connected aborted
10+
'ECONNRESET',
11+
]
12+
13+
if (IGNORED_ERRORS.includes(error.code)) {
14+
return false
15+
}
16+
17+
// "TypeError: terminated" is thrown by Node.js's undici fetch implementation
18+
// when a connection is aborted by the remote server. This is a transient
19+
// network error (similar to ECONNRESET) that occurs during proxied requests
20+
// to archived enterprise pages and shouldn't be reported to Sentry.
21+
if (error.name === 'TypeError' && error.message === 'terminated') {
22+
return false
23+
}
24+
25+
// We should log this exception
26+
return true
27+
}

src/observability/middleware/handle-errors.ts

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { NextFunction, Response } from 'express'
22

33
import FailBot from '../lib/failbot'
4+
import { shouldLogException, type ErrorWithCode } from '../lib/should-log-exception'
45
import { nextApp } from '@/frame/middleware/next'
56
import { setFastlySurrogateKey, SURROGATE_ENUMS } from '@/frame/middleware/set-fastly-surrogate-key'
67
import { errorCacheControl } from '@/frame/middleware/cache-control'
@@ -9,26 +10,6 @@ import { ExtendedRequest } from '@/types'
910

1011
const DEBUG_MIDDLEWARE_TESTS = Boolean(JSON.parse(process.env.DEBUG_MIDDLEWARE_TESTS || 'false'))
1112

12-
type ErrorWithCode = Error & {
13-
code: string
14-
statusCode?: number
15-
status?: string
16-
}
17-
18-
function shouldLogException(error: ErrorWithCode) {
19-
const IGNORED_ERRORS = [
20-
// Client connected aborted
21-
'ECONNRESET',
22-
]
23-
24-
if (IGNORED_ERRORS.includes(error.code)) {
25-
return false
26-
}
27-
28-
// We should log this exception
29-
return true
30-
}
31-
3213
async function logException(error: ErrorWithCode, req: ExtendedRequest) {
3314
if (process.env.NODE_ENV !== 'test' && shouldLogException(error)) {
3415
await FailBot.report(error, {
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { describe, expect, test } from 'vitest'
2+
3+
import { shouldLogException, type ErrorWithCode } from '../lib/should-log-exception'
4+
5+
// Helper function to create test errors with code property
6+
function createError(message: string, name: string = 'Error', code: string = ''): ErrorWithCode {
7+
const error = new Error(message) as ErrorWithCode
8+
error.name = name
9+
error.code = code
10+
return error
11+
}
12+
13+
describe('shouldLogException', () => {
14+
describe('ECONNRESET errors', () => {
15+
test('should not log ECONNRESET errors', () => {
16+
const error = createError('Connection reset', 'Error', 'ECONNRESET')
17+
18+
expect(shouldLogException(error)).toBe(false)
19+
})
20+
})
21+
22+
describe('TypeError: terminated filtering', () => {
23+
test('should not log TypeError with exact message "terminated"', () => {
24+
const error = createError('terminated', 'TypeError')
25+
26+
expect(shouldLogException(error)).toBe(false)
27+
})
28+
29+
test('should log TypeError with different message', () => {
30+
const error = createError('Cannot read property', 'TypeError')
31+
32+
expect(shouldLogException(error)).toBe(true)
33+
})
34+
35+
test('should log TypeError with partial "terminated" message', () => {
36+
const error = createError('connection terminated unexpectedly', 'TypeError')
37+
38+
expect(shouldLogException(error)).toBe(true)
39+
})
40+
41+
test('should log non-TypeError with "terminated" message', () => {
42+
const error = createError('terminated', 'Error')
43+
44+
expect(shouldLogException(error)).toBe(true)
45+
})
46+
})
47+
48+
describe('regular errors', () => {
49+
test('should log regular errors', () => {
50+
const error = createError('Something went wrong', 'Error')
51+
52+
expect(shouldLogException(error)).toBe(true)
53+
})
54+
55+
test('should log errors with no code', () => {
56+
const error = createError('Test error', 'Error')
57+
58+
expect(shouldLogException(error)).toBe(true)
59+
})
60+
})
61+
})

0 commit comments

Comments
 (0)