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

supabase / storage / 22858730975

09 Mar 2026 02:38PM UTC coverage: 76.711% (+0.5%) from 76.206%
22858730975

Pull #875

github

web-flow
Merge 6feb42ab3 into 53462ff99
Pull Request #875: feat: support unicode in object names

4212 of 5944 branches covered (70.86%)

Branch coverage included in aggregate %.

377 of 446 new or added lines in 22 files covered. (84.53%)

1 existing line in 1 file now uncovered.

27218 of 35028 relevant lines covered (77.7%)

200.69 hits per line

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

70.65
/src/internal/errors/codes.ts
1
import { StorageBackendError } from './storage-error'
2✔
2

2✔
3
function toWellFormedString(value: string): string {
8✔
4
  const maybeToWellFormed = (value as unknown as { toWellFormed?: () => string }).toWellFormed
8✔
5
  if (typeof maybeToWellFormed === 'function') {
8✔
6
    return maybeToWellFormed.call(value)
8✔
7
  }
8✔
NEW
8

×
NEW
9
  let normalized = ''
×
NEW
10
  for (let i = 0; i < value.length; i++) {
×
NEW
11
    const currentCodeUnit = value.charCodeAt(i)
×
NEW
12

×
NEW
13
    if (currentCodeUnit >= 0xd800 && currentCodeUnit <= 0xdbff) {
×
NEW
14
      const nextCodeUnit = value.charCodeAt(i + 1)
×
NEW
15
      if (i + 1 < value.length && nextCodeUnit >= 0xdc00 && nextCodeUnit <= 0xdfff) {
×
NEW
16
        normalized += value[i] + value[i + 1]
×
NEW
17
        i += 1
×
NEW
18
      } else {
×
NEW
19
        normalized += '\uFFFD'
×
NEW
20
      }
×
NEW
21
      continue
×
NEW
22
    }
×
NEW
23

×
NEW
24
    if (currentCodeUnit >= 0xdc00 && currentCodeUnit <= 0xdfff) {
×
NEW
25
      normalized += '\uFFFD'
×
NEW
26
      continue
×
NEW
27
    }
×
NEW
28

×
NEW
29
    normalized += value[i]
×
NEW
30
  }
×
NEW
31

×
NEW
32
  return normalized
×
NEW
33
}
×
34

2✔
35
function safeEncodeURIComponent(value: string): string {
8✔
36
  try {
8✔
37
    return encodeURIComponent(value)
8✔
38
  } catch {
8!
NEW
39
    return encodeURIComponent(toWellFormedString(value))
×
NEW
40
  }
×
41
}
8✔
42

2✔
43
export enum ErrorCode {
2✔
44
  NoSuchBucket = 'NoSuchBucket',
2✔
45
  NoSuchKey = 'NoSuchKey',
2✔
46
  NoSuchUpload = 'NoSuchUpload',
2✔
47
  InvalidJWT = 'InvalidJWT',
2✔
48
  InvalidRequest = 'InvalidRequest',
2✔
49
  TenantNotFound = 'TenantNotFound',
2✔
50
  EntityTooLarge = 'EntityTooLarge',
2✔
51
  InternalError = 'InternalError',
2✔
52
  ResourceAlreadyExists = 'ResourceAlreadyExists',
2✔
53
  ResourceNotEmpty = 'ResourceNotEmpty',
2✔
54
  InvalidBucketName = 'InvalidBucketName',
2✔
55
  InvalidKey = 'InvalidKey',
2✔
56
  InvalidRange = 'InvalidRange',
2✔
57
  InvalidMimeType = 'InvalidMimeType',
2✔
58
  InvalidUploadId = 'InvalidUploadId',
2✔
59
  KeyAlreadyExists = 'KeyAlreadyExists',
2✔
60
  BucketAlreadyExists = 'BucketAlreadyExists',
2✔
61
  DatabaseTimeout = 'DatabaseTimeout',
2✔
62
  InvalidSignature = 'InvalidSignature',
2✔
63
  ExpiredToken = 'ExpiredToken',
2✔
64
  SignatureDoesNotMatch = 'SignatureDoesNotMatch',
2✔
65
  AccessDenied = 'AccessDenied',
2✔
66
  ResourceLocked = 'ResourceLocked',
2✔
67
  DatabaseError = 'DatabaseError',
2✔
68
  TransactionError = 'TransactionError',
2✔
69
  MissingContentLength = 'MissingContentLength',
2✔
70
  MissingParameter = 'MissingParameter',
2✔
71
  InvalidParameter = 'InvalidParameter',
2✔
72
  InvalidUploadSignature = 'InvalidUploadSignature',
2✔
73
  LockTimeout = 'LockTimeout',
2✔
74
  S3Error = 'S3Error',
2✔
75
  S3InvalidAccessKeyId = 'InvalidAccessKeyId',
2✔
76
  S3MaximumCredentialsLimit = 'MaximumCredentialsLimit',
2✔
77
  InvalidChecksum = 'InvalidChecksum',
2✔
78
  MissingPart = 'MissingPart',
2✔
79
  SlowDown = 'SlowDown',
2✔
80
  TusError = 'TusError',
2✔
81
  Aborted = 'Aborted',
2✔
82
  AbortedTerminate = 'AbortedTerminate',
2✔
83
  FeatureNotEnabled = 'FeatureNotEnabled',
2✔
84
  NotSupported = 'NotSupported',
2✔
85
  IcebergMaximumResourceLimit = 'IcebergMaximumResourceLimit',
2✔
86
  IcebergResourceNotEmpty = 'IcebergResourceNotEmpty',
2✔
87
  NoSuchCatalog = 'NoSuchCatalog',
2✔
88

2✔
89
  S3VectorConflictException = 'ConflictException',
2✔
90
  S3VectorNotFoundException = 'NotFoundException',
2✔
91
  S3VectorBucketNotEmpty = 'VectorBucketNotEmpty',
2✔
92
  S3VectorMaxBucketsExceeded = 'S3VectorMaxBucketsExceeded',
2✔
93
  S3VectorMaxIndexesExceeded = 'S3VectorMaxIndexesExceeded',
2✔
94
  NoAvailableShard = 'NoAvailableShard',
2✔
95
  ShardNotFound = 'ShardNotFound',
2✔
96
}
2✔
97

2✔
98
export const ERRORS = {
2✔
99
  BucketNotEmpty: (bucket: string, e?: Error) =>
2✔
100
    new StorageBackendError({
2✔
101
      code: ErrorCode.ResourceNotEmpty,
2✔
102
      resource: bucket,
2✔
103
      httpStatusCode: 409,
2✔
104
      message: `The bucket you tried to delete is not empty`,
2✔
105
      originalError: e,
2✔
106
    }),
2✔
107
  IcebergMaximumResourceLimit: (limit: number, e?: Error) =>
2✔
108
    new StorageBackendError({
×
109
      code: ErrorCode.IcebergMaximumResourceLimit,
×
110
      httpStatusCode: 409,
×
111
      message: `The maximum number of this resource ${limit} is reached`,
×
112
      originalError: e,
×
113
    }),
2✔
114
  IcebergResourceNotEmpty: (resource: string, name: string, e?: Error) =>
2✔
115
    new StorageBackendError({
×
116
      code: ErrorCode.IcebergResourceNotEmpty,
×
117
      httpStatusCode: 400,
×
118
      message: `The resource ${resource}: ${name} is not empty`,
×
119
      originalError: e,
×
120
    }),
2✔
121
  FeatureNotEnabled: (resource: string, feature: string, e?: Error) =>
2✔
122
    new StorageBackendError({
×
123
      code: ErrorCode.InvalidRequest,
×
124
      resource,
×
125
      httpStatusCode: 409,
×
126
      message: `The feature ${feature} is not enabled for this resource`,
×
127
      originalError: e,
×
128
    }),
2✔
129
  NotSupported: (feature: string, e?: Error) =>
2✔
130
    new StorageBackendError({
×
131
      code: ErrorCode.InvalidRequest,
×
132
      httpStatusCode: 409,
×
133
      message: `The feature ${feature} is not enabled for this resource`,
×
134
      originalError: e,
×
135
    }),
2✔
136
  UnableToEmptyBucket: (bucket: string, msg: string) =>
2✔
137
    new StorageBackendError({
×
138
      code: ErrorCode.InvalidRequest,
×
139
      resource: bucket,
×
140
      httpStatusCode: 409,
×
141
      message: msg,
×
142
    }),
2✔
143
  NoSuchBucket: (bucket: string, e?: Error) =>
2✔
144
    new StorageBackendError({
18✔
145
      code: ErrorCode.NoSuchBucket,
18✔
146
      resource: bucket,
18✔
147
      error: 'Bucket not found',
18✔
148
      httpStatusCode: 404,
18✔
149
      message: `Bucket not found`,
18✔
150
      originalError: e,
18✔
151
    }),
2✔
152
  NoSuchUpload: (uploadId: string, e?: Error) =>
2✔
153
    new StorageBackendError({
2✔
154
      code: ErrorCode.NoSuchUpload,
2✔
155
      resource: uploadId,
2✔
156
      httpStatusCode: 404,
2✔
157
      message: `Upload not found`,
2✔
158
      originalError: e,
2✔
159
    }),
2✔
160
  NoSuchKey: (resource: string, e?: Error) =>
2✔
161
    new StorageBackendError({
44✔
162
      code: ErrorCode.NoSuchKey,
44✔
163
      resource,
44✔
164
      error: 'not_found',
44✔
165
      httpStatusCode: 404,
44✔
166
      message: `Object not found`,
44✔
167
      originalError: e,
44✔
168
    }),
2✔
169

2✔
170
  MissingParameter: (parameter: string, e?: Error) =>
2✔
171
    new StorageBackendError({
4✔
172
      code: ErrorCode.MissingParameter,
4✔
173
      httpStatusCode: 400,
4✔
174
      message: `Missing Required Parameter ${parameter}`,
4✔
175
      originalError: e,
4✔
176
    }),
2✔
177

2✔
178
  InvalidParameter: (parameter: string, opts?: { error?: Error; message?: string }) =>
2✔
179
    new StorageBackendError({
2✔
180
      code: ErrorCode.MissingParameter,
2✔
181
      httpStatusCode: 400,
2✔
182
      message: opts?.message || `Invalid Parameter ${parameter}`,
2!
183
      originalError: opts?.error,
2!
184
    }),
2✔
185

2✔
186
  InvalidJWT: (e?: Error) =>
2✔
187
    new StorageBackendError({
8✔
188
      code: ErrorCode.InvalidJWT,
8✔
189
      httpStatusCode: 400,
8✔
190
      message: e?.message || 'Invalid JWT',
8!
191
    }),
2✔
192

2✔
193
  MissingContentLength: (e?: Error) =>
2✔
194
    new StorageBackendError({
×
195
      code: ErrorCode.MissingContentLength,
×
196
      httpStatusCode: 400,
×
197
      message: e?.message || 'You must provide the Content-Length HTTP header.',
×
198
    }),
2✔
199

2✔
200
  AccessDenied: (action: string, e?: Error) =>
2✔
201
    new StorageBackendError({
2✔
202
      error: 'Unauthorized',
2✔
203
      code: ErrorCode.AccessDenied,
2✔
204
      httpStatusCode: 403,
2✔
205
      message: action || 'Access denied',
2!
206
      originalError: e,
2✔
207
    }),
2✔
208

2✔
209
  ResourceAlreadyExists: (e?: Error) =>
2✔
210
    new StorageBackendError({
10✔
211
      error: 'Duplicate',
10✔
212
      code: ErrorCode.ResourceAlreadyExists,
10✔
213
      httpStatusCode: 409,
10✔
214
      message: 'The resource already exists',
10✔
215
      originalError: e,
10✔
216
    }),
2✔
217

2✔
218
  MetadataRequired: (e?: Error) =>
2✔
219
    new StorageBackendError({
×
220
      code: ErrorCode.InvalidRequest,
×
221
      httpStatusCode: 400,
×
222
      message: 'Metadata header is required',
×
223
      originalError: e,
×
224
    }),
2✔
225

2✔
226
  SignatureDoesNotMatch: (message?: string) =>
2✔
227
    new StorageBackendError({
×
228
      code: ErrorCode.SignatureDoesNotMatch,
×
229
      httpStatusCode: 403,
×
230
      message: message || 'Signature does not match',
×
231
    }),
2✔
232

2✔
233
  InvalidSignature: (message?: string, e?: Error) =>
2✔
234
    new StorageBackendError({
6✔
235
      code: ErrorCode.InvalidSignature,
6✔
236
      httpStatusCode: 400,
6✔
237
      message: message || 'Invalid signature',
6✔
238
      originalError: e,
6✔
239
    }),
2✔
240

2✔
241
  ExpiredSignature: (e?: Error) =>
2✔
242
    new StorageBackendError({
2✔
243
      code: ErrorCode.ExpiredToken,
2✔
244
      httpStatusCode: 400,
2✔
245
      message: 'The provided token has expired.',
2✔
246
      originalError: e,
2✔
247
    }),
2✔
248

2✔
249
  InvalidXForwardedHeader: (message?: string, e?: Error) =>
2✔
250
    new StorageBackendError({
4✔
251
      code: ErrorCode.InvalidRequest,
4✔
252
      httpStatusCode: 400,
4✔
253
      message: message || 'Invalid X-Forwarded-Host header',
4!
254
      originalError: e,
4✔
255
    }),
2✔
256

2✔
257
  InvalidTenantId: (e?: Error) =>
2✔
258
    new StorageBackendError({
2✔
259
      code: ErrorCode.TenantNotFound,
2✔
260
      httpStatusCode: 400,
2✔
261
      message: e?.message || 'Invalid tenant id',
2!
262
      originalError: e,
2✔
263
    }),
2✔
264

2✔
265
  InvalidUploadId: (message?: string, e?: Error) =>
2✔
266
    new StorageBackendError({
×
267
      code: ErrorCode.InvalidUploadId,
×
268
      httpStatusCode: 400,
×
269
      message: message || 'Invalid upload id',
×
270
      originalError: e,
×
271
    }),
2✔
272

2✔
273
  TusError: (message: string, statusCode: number) =>
2✔
274
    new StorageBackendError({
6✔
275
      code: ErrorCode.TusError,
6✔
276
      httpStatusCode: statusCode,
6✔
277
      message,
6✔
278
    }),
2✔
279

2✔
280
  MissingTenantConfig: (tenantId: string) =>
2✔
281
    new StorageBackendError({
2✔
282
      code: ErrorCode.TenantNotFound,
2✔
283
      httpStatusCode: 400,
2✔
284
      message: `Missing tenant config for tenant ${tenantId}`,
2✔
285
    }),
2✔
286

2✔
287
  InvalidMimeType: (mimeType: string) =>
2✔
288
    new StorageBackendError({
4✔
289
      error: 'invalid_mime_type',
4✔
290
      code: ErrorCode.InvalidMimeType,
4✔
291
      httpStatusCode: 415,
4✔
292
      message: `mime type ${mimeType} is not supported`,
4✔
293
    }),
2✔
294

2✔
295
  InvalidXRobotsTag: (message: string) =>
2✔
296
    new StorageBackendError({
2✔
297
      error: 'invalid_x_robots_tag',
2✔
298
      code: ErrorCode.InvalidRequest,
2✔
299
      httpStatusCode: 400,
2✔
300
      message: `Invalid X-Robots-Tag header: ${message}`,
2✔
301
    }),
2✔
302

2✔
303
  InvalidRange: () =>
2✔
304
    new StorageBackendError({
×
305
      error: 'invalid_range',
×
306
      code: ErrorCode.InvalidRange,
×
307
      httpStatusCode: 400,
×
308
      message: `invalid range provided`,
×
309
    }),
2✔
310

2✔
311
  EntityTooLarge: (e?: Error, entity = 'object') =>
2✔
312
    new StorageBackendError({
8✔
313
      error: 'Payload too large',
8✔
314
      code: ErrorCode.EntityTooLarge,
8✔
315
      httpStatusCode: 413,
8✔
316
      message: `The ${entity} exceeded the maximum allowed size`,
8✔
317
      originalError: e,
8✔
318
    }),
2✔
319

2✔
320
  InternalError: (e?: Error, message?: string) =>
2✔
321
    new StorageBackendError({
×
322
      code: ErrorCode.InternalError,
×
323
      httpStatusCode: 500,
×
324
      message: message || 'Internal server error',
×
325
      originalError: e,
×
326
    }),
2✔
327

2✔
328
  ImageProcessingError: (statusCode: number, message: string, e?: Error) =>
2✔
329
    new StorageBackendError({
×
330
      code: statusCode > 499 ? ErrorCode.InternalError : ErrorCode.InvalidRequest,
×
331
      httpStatusCode: statusCode,
×
332
      message,
×
333
      originalError: e,
×
334
    }),
2✔
335

2✔
336
  InvalidBucketName: (bucket: string, e?: Error) =>
2✔
337
    new StorageBackendError({
6✔
338
      error: 'Invalid Input',
6✔
339
      code: ErrorCode.InvalidBucketName,
6✔
340
      resource: bucket,
6✔
341
      httpStatusCode: 400,
6✔
342
      message: `Bucket name invalid`,
6✔
343
      originalError: e,
6✔
344
    }),
2✔
345

2✔
346
  InvalidFileSizeLimit: (e?: Error) =>
2✔
347
    new StorageBackendError({
×
348
      code: ErrorCode.InvalidRequest,
×
349
      httpStatusCode: 400,
×
350
      message: e?.message || 'Invalid file size format, hint: use 20GB / 20MB / 30KB / 3B',
×
351
      originalError: e,
×
352
    }),
2✔
353

2✔
354
  InvalidUploadSignature: (e?: Error) =>
2✔
355
    new StorageBackendError({
×
356
      code: ErrorCode.InvalidUploadSignature,
×
357
      httpStatusCode: 400,
×
358
      message: e?.message || 'Invalid upload Signature',
×
359
      originalError: e,
×
360
    }),
2✔
361

2✔
362
  InvalidKey: (key: string, e?: Error) =>
2✔
363
    new StorageBackendError({
8✔
364
      code: ErrorCode.InvalidKey,
8✔
365
      resource: key,
8✔
366
      httpStatusCode: 400,
8✔
367
      message: `Invalid key: ${safeEncodeURIComponent(key)}`,
8✔
368
      originalError: e,
8✔
369
    }),
2✔
370

2✔
371
  KeyAlreadyExists: (key: string, e?: Error) =>
2✔
372
    new StorageBackendError({
8✔
373
      code: ErrorCode.KeyAlreadyExists,
8✔
374
      resource: key,
8✔
375
      error: 'Duplicate',
8✔
376
      httpStatusCode: 409,
8✔
377
      message: `The resource already exists`,
8✔
378
      originalError: e,
8✔
379
    }),
2✔
380

2✔
381
  BucketAlreadyExists: (bucket: string, e?: Error) =>
2✔
382
    new StorageBackendError({
2✔
383
      code: ErrorCode.BucketAlreadyExists,
2✔
384
      resource: bucket,
2✔
385
      error: 'Duplicate',
2✔
386
      httpStatusCode: 409,
2✔
387
      message: `The resource already exists`,
2✔
388
      originalError: e,
2✔
389
    }),
2✔
390

2✔
391
  NoContentProvided: (e?: Error) =>
2✔
392
    new StorageBackendError({
×
393
      code: ErrorCode.InvalidRequest,
×
394
      httpStatusCode: 400,
×
395
      message: e?.message || 'No content provided',
×
396
      originalError: e,
×
397
    }),
2✔
398

2✔
399
  DatabaseTimeout: (e?: Error) =>
2✔
400
    StorageBackendError.withStatusCode(544, {
×
401
      code: ErrorCode.DatabaseTimeout,
×
402
      httpStatusCode: 544,
×
403
      message: 'The connection to the database timed out',
×
404
      originalError: e,
×
405
    }),
2✔
406

2✔
407
  ResourceLocked: (e?: Error) =>
2✔
408
    new StorageBackendError({
×
409
      code: ErrorCode.ResourceLocked,
×
410
      httpStatusCode: 423,
×
411
      message: `The resource is locked`,
×
412
      originalError: e,
×
413
    }),
2✔
414

2✔
415
  RelatedResourceNotFound: (e?: Error) =>
2✔
416
    new StorageBackendError({
×
417
      code: ErrorCode.InvalidRequest,
×
418
      httpStatusCode: 404,
×
419
      message: `The related resource does not exist`,
×
420
      originalError: e,
×
421
    }),
2✔
422

2✔
423
  TransactionError: (message: string, err?: Error) =>
2✔
424
    new StorageBackendError({
×
425
      code: ErrorCode.TransactionError,
×
426
      httpStatusCode: 409,
×
427
      message,
×
428
      originalError: err,
×
429
    }),
2✔
430

2✔
431
  DatabaseError: (message: string, err?: Error) =>
2✔
432
    new StorageBackendError({
×
433
      code: ErrorCode.DatabaseError,
×
434
      httpStatusCode: 500,
×
435
      message,
×
436
      originalError: err,
×
437
    }),
2✔
438

2✔
439
  LockTimeout: (err?: Error) =>
2✔
440
    new StorageBackendError({
4✔
441
      error: 'acquiring_lock_timeout',
4✔
442
      code: ErrorCode.LockTimeout,
4✔
443
      httpStatusCode: 503,
4✔
444
      message: 'acquiring lock timeout',
4✔
445
      originalError: err,
4✔
446
    }),
2✔
447

2✔
448
  MissingS3Credentials: () =>
2✔
449
    new StorageBackendError({
2✔
450
      code: ErrorCode.S3InvalidAccessKeyId,
2✔
451
      httpStatusCode: 403,
2✔
452
      message: 'The Access Key Id you provided does not exist in our records.',
2✔
453
    }),
2✔
454

2✔
455
  MaximumCredentialsLimit: () =>
2✔
456
    new StorageBackendError({
2✔
457
      code: ErrorCode.S3MaximumCredentialsLimit,
2✔
458
      httpStatusCode: 400,
2✔
459
      message: 'You have reached the maximum number of credentials allowed',
2✔
460
    }),
2✔
461

2✔
462
  InvalidChecksum: (message: string) =>
2✔
463
    new StorageBackendError({
×
464
      code: ErrorCode.InvalidChecksum,
×
465
      httpStatusCode: 400,
×
466
      message,
×
467
    }),
2✔
468

2✔
469
  MissingPart: (partNumber: number, uploadId: string) =>
2✔
470
    new StorageBackendError({
×
471
      code: ErrorCode.MissingPart,
×
472
      httpStatusCode: 400,
×
473
      message: `Part ${partNumber} is missing for upload id ${uploadId}`,
×
474
    }),
2✔
475

2✔
476
  Aborted: (message: string, originalError?: unknown) =>
2✔
477
    new StorageBackendError({
×
478
      code: ErrorCode.Aborted,
×
479
      httpStatusCode: 500,
×
480
      message,
×
481
      originalError,
×
482
    }),
2✔
483
  AbortedTerminate: (message: string, originalError?: unknown) =>
2✔
484
    new StorageBackendError({
×
485
      code: ErrorCode.AbortedTerminate,
×
486
      httpStatusCode: 500,
×
487
      message,
×
488
      originalError,
×
489
    }),
2✔
490
  NoSuchCatalog: (name: string) => {
2✔
491
    return new StorageBackendError({
×
492
      code: ErrorCode.NoSuchCatalog,
×
493
      httpStatusCode: 404,
×
494
      message: `Catalog name "${name}" not found`,
×
495
    })
×
496
  },
2✔
497
  S3VectorConflictException(resource: string, name: string) {
2✔
498
    return new StorageBackendError({
2✔
499
      code: ErrorCode.S3VectorConflictException,
2✔
500
      httpStatusCode: 409,
2✔
501
      message: `${resource} "${name}" already exists`,
2✔
502
    })
2✔
503
  },
2✔
504
  S3VectorNotFoundException(resource: string, name: string) {
2✔
505
    return new StorageBackendError({
16✔
506
      code: ErrorCode.S3VectorNotFoundException,
16✔
507
      httpStatusCode: 404,
16✔
508
      message: `resource "${name}" not found`,
16✔
509
    })
16✔
510
  },
2✔
511
  S3VectorBucketNotEmpty(name: string) {
2✔
512
    return new StorageBackendError({
2✔
513
      code: ErrorCode.S3VectorBucketNotEmpty,
2✔
514
      httpStatusCode: 400,
2✔
515
      message: `Vector Bucket "${name}" not empty`,
2✔
516
    })
2✔
517
  },
2✔
518
  S3VectorMaxBucketsExceeded(maxBuckets: number) {
2✔
519
    return new StorageBackendError({
4✔
520
      code: ErrorCode.S3VectorMaxBucketsExceeded,
4✔
521
      httpStatusCode: 400,
4✔
522
      message: `Maximum number of buckets exceeded. Max allowed is ${maxBuckets}. Contact support to increase your limit.`,
4✔
523
    })
4✔
524
  },
2✔
525
  S3VectorMaxIndexesExceeded(maxIndexes: number) {
2✔
526
    return new StorageBackendError({
×
527
      code: ErrorCode.S3VectorMaxIndexesExceeded,
×
528
      httpStatusCode: 400,
×
529
      message: `Maximum number of indexes exceeded. Max allowed is ${maxIndexes}. Contact support to increase your limit.`,
×
530
    })
×
531
  },
2✔
532
  NoAvailableShard() {
2✔
533
    return new StorageBackendError({
×
534
      code: ErrorCode.NoAvailableShard,
×
535
      httpStatusCode: 500,
×
536
      message: `No available shards are available to host the resource. Please try again later.`,
×
537
    })
×
538
  },
2✔
539
  ShardNotFound(shardId: string) {
2✔
540
    return new StorageBackendError({
×
541
      code: ErrorCode.ShardNotFound,
×
542
      httpStatusCode: 404,
×
543
      message: `Shard not found: ${shardId}`,
×
544
    })
×
545
  },
2✔
546
}
2✔
547

2✔
548
export function isStorageError(errorType: ErrorCode, error: any): error is StorageBackendError {
16✔
549
  return error instanceof StorageBackendError && error.code === errorType
16✔
550
}
16✔
551

2✔
552
export function normalizeRawError(error: any) {
4✔
553
  if (error instanceof Error) {
4✔
554
    const statusCode =
4✔
555
      error instanceof StorageBackendError && error.httpStatusCode ? error.httpStatusCode : 0
4!
556
    return {
4✔
557
      raw: JSON.stringify(error),
4✔
558
      name: error.name,
4✔
559
      message: error.message,
4✔
560
      stack: error.stack,
4✔
561
      statusCode,
4✔
562
    }
4✔
563
  }
4✔
564

×
565
  try {
×
566
    return {
×
567
      raw: JSON.stringify(error),
×
568
    }
×
569
  } catch (e) {
×
570
    return {
×
571
      raw: 'Failed to stringify error',
×
572
    }
×
573
  }
×
574
}
4✔
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