Skip to main content
avatar.go

Every failure the SDK reports on purpose is a *blob.Error. Its codes are the ones the TypeScript SDK and the browser client use, so an error returned from your Go handler reaches a React hook with its code intact. The codes, their statuses and when each one is returned are on Errors.


Matching it#

Three ways to ask, all of which look through wrapped errors:

  • errors.As(err, &be) gives you the *blob.Error and its fields.
  • errors.Is(err, blob.ErrNotFound) compares the code only. The sentinels are ErrNotFound, ErrAlreadyExists, ErrConflict, ErrTooLarge, ErrInvalidInput, ErrUnauthorized, ErrForbidden and ErrContentTypeDenied.
  • blob.HasCode(err, code) works for every code, including the ones without a sentinel.

ErrorCode is a string type, and every code has a constant: CodeNotFound, CodePartialDelete, CodeMintBackoff, and so on.

A canceled or expired ctx is returned as the context’s own error, not a *blob.Error, so errors.Is(err, context.Canceled) finds it.


Fields#

FieldTypeSet by
CodeErrorCodeAlways. One of the codes.
StatusintAlways.
MessagestringAlways. See Messages.
HintstringAny code. See Hints.
Failed[]stringpartial_delete: the paths that survived the delete.
ETagstringalready_exists: the etag of what is already there.
Size*int64already_exists: the size of what is already there.
RetryAftertime.Durationmint_backoff: how long the credential service asked the caller to wait. On another code, only when you set it yourself.

The underlying error, when there was one, is the wrapped cause that errors.Unwrap returns: a network error, storage’s own message, or the reason Upstash refused to sign for a suspended or read-only bucket. A move_left_a_copy wraps the failed delete. The cause is not sent in the JSON, except that an error from an upload handler’s Input becomes the message.

Built-in hints#

CodeBuilt-in hint
signature_mismatchthe upload did not match what was authorized, usually a different size or content type
length_requiredpass 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.


Returning one#

NewError(code, ErrorOptions) builds one the way the SDK does: the code’s default message and hint, the message sentence-cased with the hint folded in, and the code’s status unless Status is set. ErrorOptions has Message, Hint, Status, Failed, ETag, Size, RetryAfter and Cause. Return one from an upload handler callback to refuse an upload with that code; see Refusing.

blob.ErrorFromStatus(status, opts) picks the code for a bare HTTP status, through the table on What reaches the browser, falling back to request_failed.

Answering with one#

A *blob.Error encodes to 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 (in seconds) are included when they are set. The cause never is.

The handler writes this body for you. Write it yourself to answer with a *blob.Error from a route of your own, such as one that calls Put for useServerUpload:

upload.go

Bad options are returned where they are written#

A mistake comes back as an error from the call that takes the option, and the kind of error says when to expect it:

MistakeReturns
NewBucketFromEnv() with the variable unset, an empty or malformed token, Retry.Retries below 0A plain error, from the constructor
Cache: "forever" on Optionsinvalid_input, from the constructor
An upload handler with no OnBeforeUpload, an empty non-nil Routes, a bad route name, a negative MaxSize, no tokenA plain error, from NewUploadHandler
An empty path, or one with a . or .. segment, on any Bucket methodinvalid_input
A negative Size, MaxSize, ExpiresIn or olderThan, a bad Cache on a callinvalid_input
blob.ParseSize("5mbit")invalid_input
A ContentTypes list that is empty, or holds an entry that is not a type/subtype or one of image/*, video/* and audio/*invalid_content_type_pattern, on a Put or from NewUploadHandler. On an UploadRoute, an empty list clears the handler’s instead.
A ContentType that is not a media type, on a signed URLinvalid_input

The plain errors start with blob: and are meant to stop your program at startup. NewUploadHandler wraps a *blob.Error from its options, so errors.As still finds it.

A few handler mistakes only show up while a request runs. They are logged on the handler’s Logger and answered as a 500:

  • OnBeforeUpload returned an empty Path, a negative MaxSize, or a State that encoding/json cannot encode.
  • OnBeforeUpload returned ContentTypes or a MaxSize wider than the route’s; see Narrowing per user.
  • OnBeforeUpload returned ContentTypes that is a non-nil empty slice or holds a bad entry. This one is answered as a 500 invalid_content_type_pattern and not logged. Leave the field nil to keep the route’s list.
  • OnUploadComplete returned a value that encoding/json cannot encode. The object is kept.