Skip to content
Pinner.xyz

SDK Error Handling

The SDK throws structured error classes that extend a common PinnerError base. Every error carries a machine-readable code, a human-readable message, a retryable flag, and an optional cause.

Error class hierarchy

PinnerError
├── ConfigurationError
├── AuthenticationError
├── UploadError
│   ├── NetworkError
│   ├── ValidationError
│   │   └── EmptyFileError
│   └── TimeoutError
├── PinError
│   ├── NotFoundError
│   └── RateLimitError
└── EnvironmentError

Error classes

PinnerError

The base class for all SDK errors. Every subclass inherits these properties:

PropertyTypeDescription
codestringMachine-readable error code
messagestringHuman-readable error description
retryablebooleanWhether the operation can be retried
causeError | undefinedThe underlying error that caused this one

ConfigurationError

Thrown when the SDK is misconfigured (e.g. missing JWT token).

  • Code: CONFIGURATION_ERROR
  • Retryable: false

AuthenticationError

Thrown for HTTP 401 and 403 responses when a request fails authentication or authorization.

  • Code: AUTHENTICATION_ERROR
  • Retryable: false

UploadError

Base class for upload-related errors.

  • Code: UPLOAD_ERROR
  • Retryable: set per subclass

NetworkError

Thrown when a network request fails (HTTP errors that don't map to a more specific class, or non-HTTP network failures).

  • Code: NETWORK_ERROR
  • Retryable: true

ValidationError

Thrown for HTTP 400 responses (invalid request data). Also used for HTTP 410 in the websites API (target is broken or gone).

  • Code: VALIDATION_ERROR
  • Retryable: false
  • Extra property: field?: string, the field that failed validation

EmptyFileError

Thrown when attempting to upload an empty file or stream. Extends ValidationError with field set to "file".

  • Code: EMPTY_FILE_ERROR
  • Retryable: false

TimeoutError

Thrown when a request times out.

  • Code: TIMEOUT_ERROR
  • Retryable: true

PinError

Base class for pin operation errors.

  • Code: PIN_ERROR
  • Retryable: set per subclass

NotFoundError

Thrown for HTTP 404 responses or when a pin is not found for a given CID.

  • Code: NOT_FOUND
  • Retryable: false

RateLimitError

Thrown for HTTP 429 rate-limit responses.

  • Code: RATE_LIMIT_EXCEEDED
  • Retryable: true
  • Extra property: retryAfter?: number, seconds to wait before retrying

EnvironmentError

Thrown when the runtime environment is not supported.

  • Code: ENVIRONMENT_ERROR
  • Retryable: false

HTTP-to-error mapping

The SDK maps HTTP status codes to error classes as follows:

HTTP statusError classNotes
400ValidationErrorInvalid request data
401AuthenticationErrorBad or expired JWT
403AuthenticationErrorNo permission for this resource
404NotFoundErrorResource doesn't exist
410ValidationErrorTarget is broken or gone (websites API)
429RateLimitErrorToo many requests; wait retryAfter seconds then retry
Other HTTP errorsNetworkErrorGeneric HTTP failure
Network failuresNetworkErrorNo response received

Retryability

Each error class sets the retryable flag:

Error classretryable
NetworkErrortrue
TimeoutErrortrue
RateLimitErrortrue
All othersfalse

Type guards

The SDK exports two type guards from @lumeweb/pinner:

import { isRetryable, isAuthenticationError } from "@lumeweb/pinner";
 
// Check if an error can be retried
if (isRetryable(error)) {
  // wait and retry
}
 
// Check if an error is authentication-related
if (isAuthenticationError(error)) {
  // prompt user to re-authenticate
}

You can also use instanceof checks directly:

import { NotFoundError, RateLimitError } from "@lumeweb/pinner";
 
if (error instanceof NotFoundError) {
  // handle 404
}
 
if (error instanceof RateLimitError) {
  console.log(`Retry after ${error.retryAfter} seconds`);
}

Example: Handling errors

import {
  Pinner,
  AuthenticationError,
  EmptyFileError,
  RateLimitError,
  isRetryable,
} from "@lumeweb/pinner";
 
const pinner = new Pinner({ jwt: process.env.PINNER_AUTH_TOKEN });
 
try {
  const result = await pinner.upload(file);
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error(
      "Bad or expired API key. Re-authenticate and try again."
    );
  } else if (error instanceof EmptyFileError) {
    console.error("Cannot upload an empty file.");
  } else if (error instanceof RateLimitError) {
    console.error(
      `Rate limit exceeded. Retry after ${error.retryAfter ?? 60} seconds.`
    );
  } else if (error instanceof Error && isRetryable(error as any)) {
    console.error("Transient error; retry:", error.message);
  } else {
    console.error("Upload failed:", error);
  }
}

See also