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 @upupjs/core:

typescript
import {
    UpupError,
    UpupErrorCode,
    UpupAuthError,
    UpupNetworkError,
    UpupValidationError,
    UpupQuotaError,
    UpupStorageError,
    UpupConfigError,
} from '@upupjs/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 '@upupjs/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 but the recovery mechanism does not:

  • The button shown after a failure is labelled "Resume" instead of "Retry".
  • It invokes the same retry command as a non-resumable upload, and the file re-uploads from the beginning. Every attempt requests a fresh multipart upload, and a failed attempt aborts the server-side upload rather than leaving its completed parts in place.

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 is not active in v3.1.0. Core ships a localStorage multipart-session store (24-hour TTL, corruption-tolerant), but no upload strategy calls it and the persist flag on the multipart options is never read — so a page refresh does not resume a partially-uploaded file.

For true part-level resume, including across a page refresh, use the tus protocol instead. It delegates fingerprinting and offset recovery to tus-js-client, which implements them for real. See Resumable Uploads.