• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / storage / 24212482312

09 Apr 2026 08:45PM UTC coverage: 18.916% (-61.9%) from 80.843%
24212482312

Pull #1000

github

web-flow
Merge 4729211eb into 41cfe7541
Pull Request #1000: feat: intro vitest & split units

521 of 3209 branches covered (16.24%)

Branch coverage included in aggregate %.

2 of 12 new or added lines in 1 file covered. (16.67%)

2698 existing lines in 93 files now uncovered.

1133 of 5535 relevant lines covered (20.47%)

16.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

50.0
/src/http/error-handler.ts
1
import { FastifyError } from '@fastify/error'
2
import { ErrorCode, isRenderableError, StorageBackendError, StorageError } from '@internal/errors'
3
import { FastifyInstance } from 'fastify'
4
import { DatabaseError } from 'pg'
5

6
/**
7
 * The global error handler for all the uncaught exceptions within a request.
8
 * We try our best to display meaningful information to our users
9
 * and log any error that occurs
10
 * @param app
11
 * @param options
12
 */
13
export const setErrorHandler = (
1✔
14
  app: FastifyInstance,
15
  options?: {
16
    respectStatusCode?: boolean
17
    formatter?: (error: StorageError) => Record<string, any>
18
  }
19
) => {
20
  app.setErrorHandler<Error>(function (error, request, reply) {
7✔
21
    const formatter = options?.formatter || ((e) => e)
4✔
22
    // We assign the error received.
23
    // it will be logged in the request log plugin
24
    request.executionError = error
4✔
25

26
    // database error
27
    if (
4!
28
      error instanceof DatabaseError &&
4!
29
      [
30
        'Authentication error', // supavisor specific
31
        'Max client connections reached',
32
        'remaining connection slots are reserved for non-replication superuser connections',
33
        'no more connections allowed',
34
        'sorry, too many clients already',
35
        'server login has been failing, try again later',
UNCOV
36
      ].some((msg) => (error as DatabaseError).message.includes(msg))
×
37
    ) {
38
      return reply.status(429).send(
×
39
        formatter({
40
          statusCode: `429`,
41
          error: 'too_many_connections',
42
          code: ErrorCode.SlowDown,
43
          message: 'Too many connections issued to the database',
44
        })
45
      )
46
    }
47

48
    if (isRenderableError(error)) {
4!
49
      const renderableError = error.render()
4✔
50
      const statusCode = options?.respectStatusCode
4!
51
        ? parseInt(renderableError.statusCode, 10)
52
        : error.userStatusCode
4!
53
          ? error.userStatusCode
54
          : renderableError.statusCode === '500'
×
55
            ? 500
56
            : 400
57

58
      if (
4✔
59
        renderableError.code === ErrorCode.AbortedTerminate ||
12✔
60
        (error instanceof StorageBackendError && error.shouldCloseConnection())
61
      ) {
62
        reply.header('Connection', 'close')
1✔
63

64
        reply.raw.once('finish', () => {
1✔
65
          setTimeout(() => {
1✔
UNCOV
66
            if (!request.raw.closed) {
×
UNCOV
67
              request.raw.destroy()
×
68
            }
69
          }, 3000)
70
        })
71
      }
72

73
      return reply.status(statusCode).send(
4✔
74
        formatter({
75
          ...renderableError,
76
          error: error.error || renderableError.code,
4!
77
        })
78
      )
79
    }
80

81
    // Fastify errors
UNCOV
82
    if ('statusCode' in error) {
×
UNCOV
83
      const err = error as FastifyError
×
84

UNCOV
85
      if (err.code === 'FST_ERR_CTP_INVALID_MEDIA_TYPE') {
×
UNCOV
86
        return reply.status(400).send(
×
87
          formatter({
88
            statusCode: '415',
89
            code: ErrorCode.InvalidMimeType,
90
            error: 'invalid_mime_type',
91
            message: 'Invalid Content-Type header',
92
          })
93
        )
94
      }
95

UNCOV
96
      return reply.status(err.statusCode || 500).send(
×
97
        formatter({
98
          statusCode: `${err.statusCode}`,
99
          error: err.name,
100
          code: ErrorCode.InternalError,
101
          message: err.message,
102
        })
103
      )
104
    }
105

UNCOV
106
    return reply.status(500).send(
×
107
      formatter({
108
        statusCode: '500',
109
        error: 'Internal',
110
        message: 'Internal Server Error',
111
        code: ErrorCode.InternalError,
112
      })
113
    )
114
  })
115
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc