Documentation menu

 

Error Handling

upup reports failures as a typed UpupError (or one of its subclasses). Every UpupError carries:

  • message — human-readable description
  • code — a stable string from the UpupErrorCode enum
  • retryable — whether the failure is transient and worth retrying
  • status — the originating HTTP status, when the error came from a response

Error types

Import the error classes and the code enum from @useupup/core:

typescript
import {
    UpupError,
    UpupErrorCode,
    UpupAuthError,
    UpupNetworkError,
    UpupValidationError,
    UpupQuotaError,
    UpupStorageError,
    UpupConfigError,
} from '@useupup/core'
ClassRaised whenExtra fields
UpupErrorBase class for every upup errorcode, retryable, status?
UpupValidationErrorA file fails a size / type / count checkreason, file
UpupNetworkErrorA fetch / XHR fails (marked retryable)status?
UpupStorageErrorAn S3 / storage operation failsprovider, operation
UpupAuthErrorA cloud-drive OAuth / provider call failsprovider
UpupQuotaErrorA configured quota is exceededlimit, used
UpupConfigErrorConfiguration is missing or invalid (e.g. no upload target)

The code values come from the UpupErrorCode enum. See Error Codes for the complete list with the trigger behind each one, or Error Monitoring for the codes you'll tag most often.

Inspecting an error

Upload failures surface through the core upload-error event with the full Error object and the file that failed. Narrow with instanceof, or switch on code:

typescript
import { UpupError, UpupErrorCode, UpupValidationError } from '@useupup/core'

// error is the Error object from an upload-error event (see Error Monitoring).
function describeUploadError(error: unknown): string {
    if (error instanceof UpupValidationError) {
        return `${error.file.name} rejected: ${error.reason}`
    }
    if (error instanceof UpupError) {
        if (error.code === UpupErrorCode.PRESIGN_FAILED) {
            return 'Your token endpoint returned an error.'
        }
        return error.retryable
            ? 'Transient failure — safe to retry.'
            : 'Permanent failure — needs attention.'
    }
    return 'Unknown error.'
}

Both surfaces — the headless core's upload-error event (full Error) and the React onError prop (message string) — plus wiring them into an error tracker are covered in Error Monitoring.

Retry behavior

Configure automatic retries with the maxRetries prop. Each file upload is retried up to that many times before it counts as a failure.

tsx
<UpupUploader
    provider="aws"
    uploadEndpoint="/api/upload-token"
    maxRetries={3}
/>

Once a file has exhausted its attempts and the run is marked failed, a manual "Retry" button appears in the UI. It appears whether or not maxRetries is set — that prop controls how many automatic attempts happen before the failure, not whether the manual button is offered.

Resumable upload recovery

When resumable multipart uploads are enabled (resumable={{ protocol: 'multipart' }}), the failure UI changes and so does what recovery costs:

  • The button shown after a failure is labelled "Resume" instead of "Retry".
  • It invokes the same retry command as a non-resumable upload, but the file continues from its last completed part rather than restarting. The failed attempt left its server-side parts in place on purpose, and the retry re-attaches to them through POST /multipart/resume.

Note that this is not the "Resume" button shown while a run is paused — that one is a separate control on the pause/resume path. Only the failure-state button is described here.

Part-level continuation survives a page refresh too, provided the file comes back: pair resumable with crashRecovery and the restored file re-attaches mid-transfer. It is on by default (persist: true) and degrades to a fresh upload — never to a failure — whenever the session cannot be trusted. What that costs your bucket, and the AbortIncompleteMultipartUpload lifecycle rule it obliges you to configure, are covered in Cross-reload resume.

In client mode (uploadEndpoint), where multipart cannot run, tus remains the resumable option: it delegates fingerprinting and offset recovery to tus-js-client. See Resumable Uploads.