DynamoDB TransactionCanceledException
TL;DR — 你 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;
}常見問題
我的 DynamoDB 交易為什麼被取消了? TransactWriteItems/TransactGetItems 中的某個項目失敗了 — 條件檢查、輸送量/節流限制,或與另一筆並行交易衝突 — 所以 DynamoDB 回復了整筆交易,什麼都沒寫入。每個項目的原因在 CancellationReasons 陣列中。
我要怎麼找出交易中是哪個項目失敗? 讀取 TransactionCanceledException 上的 CancellationReasons 陣列。它對每個輸入項目各有一筆、順序相同;Code 不是「None」的那一筆就是造成取消的項目。
重現方式
一筆交易中的兩次寫入,第二次由一個不可能成立的條件防護。整筆交易會回復,而每個動作的判定會出現在 CancellationReasons 中 — 與 TransactItems 按位置對齊:
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
最後於 2026-07-13 對照上方連結的官方 AWS 文件驗證。
已於 2026-07-26 對照 DynamoDB Local 2.x 與 AWS SDK for JavaScript v3.1095.0 重現 — 上方輸出為逐字原文。