or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

cache-persistence.mdconfiguration.mddecorator.mddynamodb-persistence.mderrors.mdfunction-wrapper.mdindex.mdmiddleware.mdtypes.md
tile.json

errors.mddocs/

Error Classes

The idempotency package provides comprehensive error classes for handling different failure scenarios. All errors extend from IdempotencyUnknownError.

Capabilities

Error Class Hierarchy

All idempotency errors extend from the base error class and provide specific information about different failure scenarios.

/**
 * Base error for idempotency errors.
 * Generally should not be thrown directly unless error is generic/unknown.
 */
class IdempotencyUnknownError extends Error {
  constructor(message?: string, options?: ErrorOptions);
}

/**
 * Item attempting to be inserted already exists and is not expired.
 * Thrown when a duplicate request is detected with an active record.
 */
class IdempotencyItemAlreadyExistsError extends IdempotencyUnknownError {
  /** The existing idempotency record that was found */
  public existingRecord?: IdempotencyRecord;

  constructor(
    message?: string,
    existingRecord?: IdempotencyRecord,
    options?: ErrorOptions
  );
}

/**
 * Item does not exist in persistence store.
 * Thrown when attempting to retrieve a record that doesn't exist.
 */
class IdempotencyItemNotFoundError extends IdempotencyUnknownError {
  constructor(message?: string, options?: ErrorOptions);
}

/**
 * Execution with idempotency key is already in progress.
 * Thrown when a concurrent request is detected.
 */
class IdempotencyAlreadyInProgressError extends IdempotencyUnknownError {
  /** The in-progress idempotency record */
  public existingRecord?: IdempotencyRecord;

  constructor(
    message?: string,
    existingRecord?: IdempotencyRecord,
    options?: ErrorOptions
  );
}

/**
 * An invalid status was provided.
 * Thrown when an idempotency record has an unrecognized status.
 */
class IdempotencyInvalidStatusError extends IdempotencyUnknownError {
  constructor(message?: string, options?: ErrorOptions);
}

/**
 * Payload does not match stored idempotency record.
 * Thrown when payload validation is enabled and payloads differ.
 */
class IdempotencyValidationError extends IdempotencyUnknownError {
  /** The existing record with different payload */
  public existingRecord?: IdempotencyRecord;

  constructor(
    message?: string,
    existingRecord?: IdempotencyRecord,
    options?: ErrorOptions
  );
}

/**
 * State is inconsistent across multiple requests to persistence store.
 * Thrown when the persistence layer detects inconsistent state.
 */
class IdempotencyInconsistentStateError extends IdempotencyUnknownError {
  constructor(message?: string, options?: ErrorOptions);
}

/**
 * Unrecoverable error from the data store.
 * Thrown when the persistence layer encounters a fatal error.
 */
class IdempotencyPersistenceLayerError extends IdempotencyUnknownError {
  constructor(message: string, options?: ErrorOptions);
}

/**
 * Payload does not contain an idempotency key.
 * Thrown when throwOnNoIdempotencyKey is true and key cannot be extracted.
 */
class IdempotencyKeyError extends IdempotencyUnknownError {
  constructor(message?: string, options?: ErrorOptions);
}

/**
 * Error with the persistence layer's consistency, needs to be removed.
 * Thrown when a record is corrupted or orphaned (cache persistence only).
 *
 * Note: This error class is not exported from the main package.
 * It is used internally by CachePersistenceLayer and may be thrown
 * during cache operations.
 */
class IdempotencyPersistenceConsistencyError extends IdempotencyUnknownError {
  constructor(message: string, options?: ErrorOptions);
}

Availability: This error is not directly importable from @aws-lambda-powertools/idempotency. It is used internally by the cache persistence layer.

Error Handling Examples

Handling Duplicate Requests

import {
  makeIdempotent,
  IdempotencyItemAlreadyExistsError,
} from '@aws-lambda-powertools/idempotency';
import { DynamoDBPersistenceLayer } from '@aws-lambda-powertools/idempotency/dynamodb';

const persistenceStore = new DynamoDBPersistenceLayer({
  tableName: 'idempotencyTable',
});

const myHandler = async (event: any, context: any) => {
  try {
    // Your logic
    return { statusCode: 200, body: 'Success' };
  } catch (error) {
    if (error instanceof IdempotencyItemAlreadyExistsError) {
      // A duplicate request was detected
      console.log('Duplicate request, returning cached response');
      // The error contains the existing record
      return error.existingRecord?.getResponse();
    }
    throw error;
  }
};

export const handler = makeIdempotent(myHandler, { persistenceStore });

Handling Missing Idempotency Key

import {
  makeIdempotent,
  IdempotencyConfig,
  IdempotencyKeyError,
} from '@aws-lambda-powertools/idempotency';
import { DynamoDBPersistenceLayer } from '@aws-lambda-powertools/idempotency/dynamodb';

const persistenceStore = new DynamoDBPersistenceLayer({
  tableName: 'idempotencyTable',
});

const config = new IdempotencyConfig({
  eventKeyJmesPath: 'headers."idempotency-key"',
  throwOnNoIdempotencyKey: true,
});

const myHandler = async (event: any, context: any) => {
  try {
    // Your logic
    return { statusCode: 200, body: 'Success' };
  } catch (error) {
    if (error instanceof IdempotencyKeyError) {
      // Idempotency key is missing
      return {
        statusCode: 400,
        body: JSON.stringify({
          error: 'Missing idempotency-key header',
        }),
      };
    }
    throw error;
  }
};

export const handler = makeIdempotent(myHandler, { persistenceStore, config });

Handling Validation Errors

import {
  makeIdempotent,
  IdempotencyConfig,
  IdempotencyValidationError,
} from '@aws-lambda-powertools/idempotency';
import { DynamoDBPersistenceLayer } from '@aws-lambda-powertools/idempotency/dynamodb';

const persistenceStore = new DynamoDBPersistenceLayer({
  tableName: 'idempotencyTable',
});

const config = new IdempotencyConfig({
  eventKeyJmesPath: 'orderId',
  payloadValidationJmesPath: 'orderData',
});

const myHandler = async (event: any, context: any) => {
  try {
    // Your logic
    return { statusCode: 200, body: 'Success' };
  } catch (error) {
    if (error instanceof IdempotencyValidationError) {
      // Same orderId but different orderData
      console.error('Payload validation failed');
      return {
        statusCode: 422,
        body: JSON.stringify({
          error: 'Payload mismatch for this order ID',
        }),
      };
    }
    throw error;
  }
};

export const handler = makeIdempotent(myHandler, { persistenceStore, config });

Handling Concurrent Requests

import {
  makeIdempotent,
  IdempotencyAlreadyInProgressError,
} from '@aws-lambda-powertools/idempotency';
import { DynamoDBPersistenceLayer } from '@aws-lambda-powertools/idempotency/dynamodb';

const persistenceStore = new DynamoDBPersistenceLayer({
  tableName: 'idempotencyTable',
});

const myHandler = async (event: any, context: any) => {
  try {
    // Your logic
    return { statusCode: 200, body: 'Success' };
  } catch (error) {
    if (error instanceof IdempotencyAlreadyInProgressError) {
      // Another invocation is currently processing this request
      console.log('Request already in progress');
      return {
        statusCode: 409,
        body: JSON.stringify({
          error: 'Request is currently being processed',
        }),
      };
    }
    throw error;
  }
};

export const handler = makeIdempotent(myHandler, { persistenceStore });

Generic Error Handling

import {
  makeIdempotent,
  IdempotencyUnknownError,
  IdempotencyPersistenceLayerError,
} from '@aws-lambda-powertools/idempotency';
import { DynamoDBPersistenceLayer } from '@aws-lambda-powertools/idempotency/dynamodb';

const persistenceStore = new DynamoDBPersistenceLayer({
  tableName: 'idempotencyTable',
});

const myHandler = async (event: any, context: any) => {
  try {
    // Your logic
    return { statusCode: 200, body: 'Success' };
  } catch (error) {
    if (error instanceof IdempotencyPersistenceLayerError) {
      // Fatal error from persistence store
      console.error('Persistence layer error:', error.message);
      throw error; // Retry the entire request
    }

    if (error instanceof IdempotencyUnknownError) {
      // Generic idempotency error
      console.error('Idempotency error:', error.message);
      throw error;
    }

    throw error;
  }
};

export const handler = makeIdempotent(myHandler, { persistenceStore });

Error Scenarios

IdempotencyItemAlreadyExistsError

When: Duplicate request detected with an active (non-expired) record

Typical causes:

  • Client retries the same request
  • Load balancer/API Gateway retries
  • User clicks submit button multiple times

Recovery: Return the cached response from existingRecord

IdempotencyItemNotFoundError

When: Attempting to retrieve a record that doesn't exist

Typical causes:

  • Record expired and was deleted
  • Record was manually deleted
  • First invocation for this payload

Recovery: Usually handled internally; create new record

IdempotencyAlreadyInProgressError

When: Concurrent request for the same idempotency key

Typical causes:

  • Multiple simultaneous requests
  • Fast retries before first request completes

Recovery: Reject request or retry after delay

IdempotencyInvalidStatusError

When: Record has unrecognized status value

Typical causes:

  • Data corruption
  • Manual record modification
  • Version mismatch

Recovery: Delete and recreate record

IdempotencyValidationError

When: Payload differs from stored record (when validation enabled)

Typical causes:

  • Same idempotency key but different payload
  • Client error/bug
  • Malicious request

Recovery: Reject request with error

IdempotencyKeyError

When: Cannot extract idempotency key and throwOnNoIdempotencyKey=true

Typical causes:

  • Missing required field
  • Invalid JMESPath expression
  • Empty payload

Recovery: Return validation error to client

IdempotencyPersistenceConsistencyError

When: Persistence layer detects corrupted or orphaned record (cache only)

Typical causes:

  • Lambda timeout left orphaned "in progress" record
  • Cache record corruption
  • Race condition during cleanup

Recovery: Usually handled internally via lock acquisition

IdempotencyPersistenceLayerError

When: Unrecoverable persistence store error

Typical causes:

  • DynamoDB throttling
  • Network errors
  • Permission issues
  • Table doesn't exist

Recovery: Retry entire request

Best Practices

  1. Catch specific errors rather than generic Error to handle idempotency issues appropriately
  2. Log error details including the existing record when available
  3. Return appropriate HTTP status codes (409 for conflicts, 422 for validation, etc.)
  4. Monitor error rates to detect configuration or integration issues
  5. Use existing record from errors that include existingRecord property