DynamoDB TransactionCanceledException
요약 — TransactWriteItems / TransactGetItems 안의 항목 하나(또는 그 이상)가 실패해 DynamoDB가 전체 트랜잭션을 롤백했습니다. 진짜 원인은 CancellationReasons 배열에 있습니다 — 이를 읽으세요. 항목별 사유 Code가 어떤 항목이 왜 실패했는지 정확히 알려 줍니다.
무엇을 의미하는가
DynamoDB 트랜잭션은 전부 아니면 전무입니다. 어떤 항목의 조건이 실패하거나, 용량을 초과하거나, 두 트랜잭션이 충돌하면 전체가 취소되고 아무것도 기록되지 않습니다. 최상위 메시지는 일반적입니다:
TransactionCanceledException: Transaction cancelled, please refer cancellation reasons for specific reasons [ConditionalCheckFailed, None, TransactionConflict]대괄호 안의 목록은 위치 기반입니다 — 트랜잭션의 항목마다 하나씩, 순서대로 대응합니다. DynamoDB는 이 예외를 HTTP 상태 400으로 반환하며, AWS SDK는 이를 자동으로 재시도하지 않습니다. 재시도가 타당한지는 사유 코드별로 여러분의 코드가 판단합니다.
왜 발생하나요 (사유 코드)
ConditionalCheckFailed— 해당 항목의ConditionExpression이 false로 평가되었습니다(ConditionalCheckFailedException 참고).TransactionConflict— 다른 동시 트랜잭션(또는 쓰기)이 같은 항목을 작업 중입니다. 백오프와 함께 재시도하세요.ProvisionedThroughputExceeded— 해당 항목의 테이블/인덱스 용량이 소진되었습니다.ThrottlingError— 테이블이나 인덱스(보통 온디맨드이며 DynamoDB가 아직 확장 중일 때)가 쓰기를 스로틀링했습니다. 백오프와 함께 재시도하세요.ValidationError— 해당 항목의 형식이 잘못되었습니다(유효하지 않은 파라미터 값, 문서 경로, 피연산자 타입, 크기 초과 등).ItemCollectionSizeLimitExceeded— LSI 항목 컬렉션이 10 GB에 도달했습니다.None— 해당 항목에는 문제가 없었습니다. 실패는 목록의 다른 곳에 있었습니다.
이것이 문서화된 전체 코드 집합입니다. 중복된 항목 키(두 액션이 같은 항목을 대상으로 하는 경우)는 취소 코드가 아니라는 점을 유념하세요 — DynamoDB는 그런 요청을 앞단에서 ValidationException으로 거부합니다.
어떻게 해결하는가
- 메시지만 보지 말고 오류에서
CancellationReasons를 읽으세요. 각 항목을 인덱스로 입력 항목에 되짚어 매핑하세요. - 코드별로 분기하세요:
ConditionalCheckFailed→ 비즈니스 로직;TransactionConflict/ThrottlingError/ProvisionedThroughputExceeded→ 지수 백오프와 함께 재시도;ValidationError→ 요청 수정. - 중복 키를 피하세요 — 하나의 트랜잭션은 같은 항목을 두 번 건드릴 수 없습니다.
항목을 손으로 편집하시나요? DynoTable의 스테이징 영역은 편집 내용을 하나의 트랜잭션 쓰기로 묶고 커밋 전에 모든 항목을 검토하게 해줍니다 — 요청을 직접 조립하지 않고도 같은 전부-아니면-전무 의미를 얻습니다.
예제
import {DynamoDBClient, TransactionCanceledException} from '@aws-sdk/client-dynamodb';
import {DynamoDBDocumentClient, TransactWriteCommand} from '@aws-sdk/lib-dynamodb';
const doc = DynamoDBDocumentClient.from(new DynamoDBClient({}));
try {
await doc.send(new TransactWriteCommand({TransactItems: [/* ... */]}));
} catch (err) {
if (err instanceof TransactionCanceledException) {
for (const [i, reason] of (err.CancellationReasons ?? []).entries()) {
if (reason.Code && reason.Code !== 'None') {
console.error(`item ${i} cancelled: ${reason.Code} — ${reason.Message}`);
}
}
}
throw err;
}FAQ
내 DynamoDB 트랜잭션은 왜 취소되었나요? TransactWriteItems/TransactGetItems 안의 한 항목이 실패했기 때문입니다 — 조건 확인, 처리량/스로틀링 한도, 또는 다른 동시 트랜잭션과의 충돌이죠 — 그래서 DynamoDB가 전체 트랜잭션을 롤백하고 아무것도 기록하지 않았습니다. 항목별 사유는 CancellationReasons 배열에 있습니다.
트랜잭션에서 어떤 항목이 실패했는지 어떻게 찾나요? TransactionCanceledException의 CancellationReasons 배열을 읽으세요. 입력 항목마다 하나씩 같은 순서로 들어 있으며, Code가 "None"이 아닌 항목이 취소를 일으킨 항목입니다.
재현하기
하나의 트랜잭션에 두 개의 쓰기를 넣고, 두 번째에는 성립할 수 없는 조건을 겁니다. 전체 트랜잭션이 롤백되고, 액션별 판정이 TransactItems와 위치가 맞춰진 채 CancellationReasons에 도착합니다:
await client.send(
new TransactWriteItemsCommand({
TransactItems: [
{Put: {TableName: 'orders', Item: {pk: {S: 'OK'}, sk: {S: 'META'}}}},
{
Put: {
TableName: 'orders',
Item: {pk: {S: 'ORDER#1'}, sk: {S: 'META'}},
ConditionExpression: 'attribute_not_exists(pk)' // ORDER#1 already exists
}
}
]
})
);실제 출력:
TransactionCanceledException: Transaction cancelled, please refer cancellation reasons for specific reasons [None, ConditionalCheckFailed]
HTTP 400
error.CancellationReasons:
[
{
"Code": "None"
},
{
"Code": "ConditionalCheckFailed",
"Message": "The conditional request failed"
}
]첫 번째 액션은 None을 보고합니다 — 그것은 실패한 것이 아니라 이웃이 실패해서 롤백된 것입니다. Code가 None이 아닌 항목만이 실제 원인을 가리키며, 그 인덱스가 여러분의 TransactItems 배열에서 문제가 된 액션의 인덱스입니다.
관련 오류
- ConditionalCheckFailedException
- ProvisionedThroughputExceededException
- 코드 예제: Node.js의 TransactWriteItems · Python(boto3) — 비교해 볼 수 있는 실행 가능한 트랜잭션.
- 학습: DynamoDB 트랜잭션
참고 자료
- TransactWriteItems — Amazon DynamoDB API Reference
- TransactGetItems — Amazon DynamoDB API Reference
- Amazon DynamoDB Transactions: How it works — Amazon DynamoDB Developer Guide
- Error handling with DynamoDB — Amazon DynamoDB Developer Guide
위에 링크된 공식 AWS 문서를 기준으로 2026-07-13에 마지막으로 검증했습니다.
2026-07-26에 DynamoDB Local 2.x와 AWS SDK for JavaScript v3.1095.0으로 재현했습니다 — 위 출력은 그대로 옮긴 것입니다.