The idempotency package provides comprehensive error classes for handling different failure scenarios. All errors extend from IdempotencyUnknownError.
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.
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 });When: Duplicate request detected with an active (non-expired) record
Typical causes:
Recovery: Return the cached response from existingRecord
When: Attempting to retrieve a record that doesn't exist
Typical causes:
Recovery: Usually handled internally; create new record
When: Concurrent request for the same idempotency key
Typical causes:
Recovery: Reject request or retry after delay
When: Record has unrecognized status value
Typical causes:
Recovery: Delete and recreate record
When: Payload differs from stored record (when validation enabled)
Typical causes:
Recovery: Reject request with error
When: Cannot extract idempotency key and throwOnNoIdempotencyKey=true
Typical causes:
Recovery: Return validation error to client
When: Persistence layer detects corrupted or orphaned record (cache only)
Typical causes:
Recovery: Usually handled internally via lock acquisition
When: Unrecoverable persistence store error
Typical causes:
Recovery: Retry entire request
Error to handle idempotency issues appropriatelyexistingRecord property