Everything the SDK throws is a BlobError. The same class and codes are used on the server, in the browser, and inside the React hooks. The codes, their statuses and when each one is raised are on Errors.
BlobError is exported from all three entrypoints: @upstash/blob, @upstash/blob/browser and @upstash/blob/react.
Use BlobError.is(), not instanceof#
An ESM copy and a CJS copy of the class are two different classes, so instanceof can return
false for an error that genuinely is one. BlobError.is() checks a Symbol.for marker instead,
which is shared across every copy of the package in the process.
is() is a type guard, so the fields are typed after it.
Fields#
| Field | Type | Set by |
|---|---|---|
code | BlobErrorCode | Always. One of the codes. |
status | number | Always. |
message | string | Always. See Messages. |
hint | string | undefined | Any code. See Hints. |
failed | string[] | undefined | partial_delete: the paths that survived the delete. |
etag | string | undefined | already_exists: the etag of what is already there. |
size | number | undefined | already_exists: the size of what is already there. |
retryAfter | number | undefined | mint_backoff: seconds the credential service asked the caller to wait. On another code, only when you set it yourself. |
cause | unknown | The underlying error, when there was one. Standard Error.cause. |
BlobErrorCode and BlobErrorOptions are exported as types from @upstash/blob. BlobErrorCode is also exported from /browser and /react.
Built-in hints#
| Code | Built-in hint |
|---|---|
signature_mismatch | the upload did not match what was authorized, usually a different size or content type |
length_required | pass { size } or { maxSize } so the length is known before the first byte |
How a hint folds into the message is on Hints fold into the message.
Throwing one#
new BlobError(code, options?) takes a message string, or { message, hint, status, failed, etag, size, retryAfter, cause }. Throw one from an upload handler callback to refuse an upload with that code; see Refusing.
Bad options are a TypeError#
An unparseable '5mbit', a missing token, a route with no onBeforeUpload: those throw a TypeError where the option is written, not a BlobError per request. So does a path with a . or .. segment.
An onBeforeUpload that returns constraints wider than the route’s also throws a TypeError, while the request runs. It is not a BlobError, so the request ends as a 500 rather than a refusal the browser can read. See Narrowing per user.
Cancel is an AbortError#
A canceled browser upload rejects with an AbortError, not a BlobError. See Errors the browser raises on its own.