Skip to content

Commit f3f3607

Browse files
committed
fix(uploads): read the not-found label from code as well as name
Azure raises a RestError whose name carries the class and whose code carries the reason, so testing name first and falling back to code only when name was absent missed BlobNotFound outright — narrower than the per-provider check it replaced.
1 parent e93bf2e commit f3f3607

5 files changed

Lines changed: 20 additions & 11 deletions

File tree

apps/sim/lib/uploads/core/errors.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ describe('isObjectNotFoundError', () => {
2424
expect(isObjectNotFoundError({ code: 404 })).toBe(true)
2525
})
2626

27+
it('reads the label from code when name carries the error class instead', () => {
28+
/** Azure raises a `RestError`; the reason lives in `code`, not `name`. */
29+
expect(isObjectNotFoundError({ name: 'RestError', code: 'BlobNotFound' })).toBe(true)
30+
expect(isObjectNotFoundError({ name: 'Error', code: 'NoSuchKey' })).toBe(true)
31+
})
32+
2733
it('matches on status alone when the provider sends no label', () => {
2834
expect(isObjectNotFoundError({ $metadata: { httpStatusCode: 404 } })).toBe(true)
2935
expect(isObjectNotFoundError({ statusCode: 404 })).toBe(true)
Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const NOT_FOUND_LABELS = new Set(['NotFound', 'NoSuchKey', 'BlobNotFound'])
2+
13
/**
24
* True when a storage provider reports that an object simply does not exist.
35
*
@@ -13,19 +15,20 @@
1315
export function isObjectNotFoundError(error: unknown): boolean {
1416
if (!error || typeof error !== 'object') return false
1517

16-
const candidate = error as {
18+
const { name, code, statusCode, $metadata } = error as {
1719
name?: unknown
1820
code?: unknown
1921
statusCode?: unknown
2022
$metadata?: { httpStatusCode?: unknown }
2123
}
2224

23-
const label = typeof candidate.name === 'string' ? candidate.name : candidate.code
24-
if (label === 'NotFound' || label === 'NoSuchKey' || label === 'BlobNotFound') return true
25+
/**
26+
* `name` and `code` are checked independently: Azure raises a `RestError` whose
27+
* `name` says nothing useful and whose `code` carries the reason, while the AWS
28+
* SDK puts the reason in `name`.
29+
*/
30+
if (typeof name === 'string' && NOT_FOUND_LABELS.has(name)) return true
31+
if (typeof code === 'string' && NOT_FOUND_LABELS.has(code)) return true
2532

26-
return (
27-
candidate.code === 404 ||
28-
candidate.statusCode === 404 ||
29-
candidate.$metadata?.httpStatusCode === 404
30-
)
33+
return code === 404 || statusCode === 404 || $metadata?.httpStatusCode === 404
3134
}

apps/sim/lib/uploads/providers/blob/client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
readNodeStreamToBufferWithLimit,
88
} from '@/lib/core/utils/stream-limits'
99
import { BLOB_CONFIG } from '@/lib/uploads/config'
10+
import { isObjectNotFoundError } from '@/lib/uploads/core/errors'
1011
import type {
1112
AzureMultipartPart,
1213
AzureMultipartUploadInit,
@@ -20,7 +21,6 @@ import type {
2021
} from '@/lib/uploads/shared/types'
2122
import { sanitizeStorageMetadata } from '@/lib/uploads/utils/file-utils'
2223
import { sanitizeFileName } from '@/executor/constants'
23-
import { isObjectNotFoundError } from '@/lib/uploads/core/errors'
2424

2525
const logger = createLogger('BlobClient')
2626
const MULTIPART_UPLOAD_ID_METADATA_KEY = 'sim_upload_id'

apps/sim/lib/uploads/providers/gcs/client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
readNodeStreamToBufferWithLimit,
99
} from '@/lib/core/utils/stream-limits'
1010
import { GCS_CONFIG } from '@/lib/uploads/config'
11+
import { isObjectNotFoundError } from '@/lib/uploads/core/errors'
1112
import type {
1213
GcsConfig,
1314
GcsMultipartPart,
@@ -24,7 +25,6 @@ import {
2425
sanitizeStorageMetadata,
2526
} from '@/lib/uploads/utils/file-utils'
2627
import { sanitizeFileName } from '@/executor/constants'
27-
import { isObjectNotFoundError } from '@/lib/uploads/core/errors'
2828

2929
const logger = createLogger('GcsClient')
3030

apps/sim/lib/uploads/providers/s3/client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
readNodeStreamToBufferWithLimit,
2121
} from '@/lib/core/utils/stream-limits'
2222
import { S3_CONFIG, S3_KB_CONFIG } from '@/lib/uploads/config'
23+
import { isObjectNotFoundError } from '@/lib/uploads/core/errors'
2324
import type {
2425
S3Config,
2526
S3MultipartPart,
@@ -36,7 +37,6 @@ import {
3637
sanitizeStorageMetadata,
3738
} from '@/lib/uploads/utils/file-utils'
3839
import { sanitizeFileName } from '@/executor/constants'
39-
import { isObjectNotFoundError } from '@/lib/uploads/core/errors'
4040

4141
let _s3Client: S3Client | null = null
4242

0 commit comments

Comments
 (0)