Every failure the SDK reports is a BlobError, an Exception subclass. Its codes are the ones the TypeScript SDK and the browser client use, so an error raised in your Python handler reaches a React hook with its code intact. The codes, their statuses and when each one is raised are on Errors.
BlobError and BlobErrorCode are exported from upstash_blob.
Catching it#
There is one BlobError class, so except BlobError and isinstance are all you need. BlobErrorCode is a Literal of every code, so an editor completes them.
Fields#
| Field | Type | Set by |
|---|---|---|
code | BlobErrorCode | Always. One of the codes. |
status | int | Always. |
message | str | Always. See Messages. |
hint | str | None | Any code. See Hints. |
failed | list[str] | None | partial_delete: the paths that survived the delete. |
etag | str | None | already_exists: the etag of what is already there. |
size | int | None | already_exists: the size of what is already there. |
retry_after | float | None | mint_backoff: seconds the credential service asked the caller to wait. On another code, only when you set it yourself. |
reason | str | None | A refusal from Upstash meant for the bucket owner, such as a suspended or read-only bucket. Never in message or to_dict(). |
The underlying error, when there was one, is the standard __cause__, set with raise ... from. A move_left_a_copy carries the failed delete there.
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 max_size= so the length is known before the first byte |
How a hint folds into the message is on Hints fold into the message.
Raising one#
BlobError(code, message=None, *, hint, status, failed, etag, size, retry_after, reason). The message is positional; everything else is a keyword. Raise one from an upload handler callback to refuse an upload with that code; see Refusing.
to_dict()#
The JSON body an upload route answers a refusal with, and what the browser client rebuilds into its own BlobError. hint, failed, etag, size and retryAfter are included when they are set. reason never is.
The handler writes this body for you. Call it yourself to answer with a BlobError from a route of your own, such as one that calls put for useServerUpload:
A BlobError also survives pickle, so it crosses a process pool or a task queue with its fields intact.
Bad options raise TypeError or ValueError#
A wrong type raises a TypeError and a value that does not parse raises a ValueError, where the option is written:
| Mistake | Raises |
|---|---|
Bucket.from_env() with the variable unset | TypeError |
retry={"retrys": 3}, content_types="image/*", max_size=True | TypeError |
max_size="5mbit", expires_in="soon", a negative size | ValueError |
A path that is empty or has a . or .. segment, on any Bucket method | ValueError |
An upload handler with no on_before_upload, an empty routes, a bad route name | TypeError, when the handler is built |
A body of an unsupported type, or one that yields str | TypeError |
cache="forever" on Bucket(...) | ValueError, from each call that stores an object |
Two option mistakes raise a BlobError instead. A content_types list that is empty, or holds an entry that is not a type/subtype or one of image/*, video/* and audio/*, raises invalid_content_type_pattern, on a put or when a handler is built. A content_type that is not a media type raises invalid_input.
The upload handler turns the path errors into invalid_input, since a path built from the browser’s filename can be the client’s doing. A few handler mistakes only show up while a request runs, and raise a TypeError that the framework answers as a 500:
on_before_uploadreturned something other than aBeforeUploadResult, or astatethat is not JSON-serializable.on_before_uploadreturnedcontent_typesor amax_sizewider than the route’s; see Narrowing per user.on_upload_completereturned a value that is not JSON-serializable.- An
UploadHandlercallback returned a coroutine; see Sync or async.