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

supabase / storage / 25825624299

13 May 2026 08:49PM UTC coverage: 75.091% (+0.04%) from 75.048%
25825624299

Pull #1106

github

web-flow
Merge 458f57636 into 028b5ba18
Pull Request #1106: fix: correctly categorize errors related to saturated project databases

4041 of 5947 branches covered (67.95%)

Branch coverage included in aggregate %.

4 of 4 new or added lines in 3 files covered. (100.0%)

3 existing lines in 3 files now uncovered.

8165 of 10308 relevant lines covered (79.21%)

413.58 hits per line

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

41.67
/src/http/routes/s3/error-handler.ts
1
import { S3ServiceException } from '@aws-sdk/client-s3'
2
import { FastifyError } from '@fastify/error'
3
import { ErrorCode, StorageBackendError } from '@internal/errors'
4
import { isDatabaseSlowDownError } from '@internal/errors/database-error'
5
import { FastifyReply } from 'fastify/types/reply'
6
import { FastifyRequest } from 'fastify/types/request'
7

8
type ValidationIssue = {
9
  instancePath?: string
10
  message?: string
11
}
12

13
export const s3ErrorHandler = (
27✔
14
  error: FastifyError | Error,
15
  request: FastifyRequest,
16
  reply: FastifyReply
17
) => {
18
  request.executionError = error
26✔
19
  const validation = getValidationIssues(error)
26✔
20

21
  const resource = request.url
26✔
22
    .split('?')[0]
23
    .replace('/s3', '')
24
    .split('/')
25
    .filter((e) => e)
81✔
26
    .join('/')
27

28
  if (validation) {
26!
29
    return reply.status(400).send({
×
30
      Error: {
31
        Resource: resource,
32
        Code: ErrorCode.InvalidRequest,
33
        Message: formatValidationError(validation).message,
34
      },
35
    })
36
  }
37

38
  if (error instanceof S3ServiceException) {
26!
39
    return reply.status(error.$metadata.httpStatusCode || 500).send({
×
40
      Error: {
41
        Resource: resource,
42
        Code: error.$response?.body.Code || ErrorCode.S3Error,
×
43
        Message: error.message,
44
      },
45
    })
46
  }
47

48
  // database error
49
  if (isDatabaseSlowDownError(error)) {
26!
UNCOV
50
    return reply.status(429).send({
×
51
      Error: {
52
        Resource: resource,
53
        Code: ErrorCode.SlowDown,
54
        Message: 'Too many connections issued to the database',
55
      },
56
    })
57
  }
58

59
  if (error instanceof StorageBackendError) {
26✔
60
    return reply.status(error.httpStatusCode || 500).send({
24!
61
      Error: {
62
        Resource: resource,
63
        Code: error.code,
64
        Message: error.message,
65
      },
66
    })
67
  }
68

69
  const statusCode =
70
    'statusCode' in error && typeof error.statusCode === 'number' ? error.statusCode : undefined
2!
71

72
  if (statusCode && statusCode >= 400 && statusCode < 500) {
26✔
73
    return reply.status(statusCode).send({
2✔
74
      Error: {
75
        Resource: resource,
76
        Code: ErrorCode.InvalidRequest,
77
        Message: error.message,
78
      },
79
    })
80
  }
81

82
  return reply.status(500).send({
×
83
    Error: {
84
      Resource: resource,
85
      Code: ErrorCode.InternalError,
86
      Message: 'Internal Server Error',
87
    },
88
  })
89
}
90

91
function isValidationIssueArray(value: unknown): value is ValidationIssue[] {
92
  return Array.isArray(value) && value.every(isValidationIssue)
×
93
}
94

95
function isValidationIssue(value: unknown): value is ValidationIssue {
96
  if (!value || typeof value !== 'object') {
×
97
    return false
×
98
  }
99

100
  const issue = value as ValidationIssue
×
101
  return (
×
102
    (issue.instancePath === undefined || typeof issue.instancePath === 'string') &&
103
    (issue.message === undefined || typeof issue.message === 'string')
104
  )
105
}
106

107
function getValidationIssues(error: FastifyError | Error): ValidationIssue[] | undefined {
108
  if (!('validation' in error)) {
26!
109
    return undefined
26✔
110
  }
111

112
  const value = error.validation
×
113
  return isValidationIssueArray(value) ? value : undefined
×
114
}
115

116
function formatValidationError(errors: readonly ValidationIssue[]) {
117
  let text = ''
×
118
  const separator = ', '
×
119

120
  for (let i = 0; i !== errors.length; ++i) {
×
121
    const e = errors[i]
×
122
    const instancePath = (e.instancePath || '').replace(/^\//, '')
×
123
    text += instancePath.split('/').join(separator) + ' ' + e.message + separator
×
124
  }
125
  return new Error(text.slice(0, -separator.length))
×
126
}
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