DynamoDB TransactionCanceledException

TL;DR — TransactWriteItems / TransactGetItems の中の1つ(または複数)のアイテムが失敗したため、DynamoDB は トランザクション全体 をロールバックしました。本当の原因は CancellationReasons 配列にあります — それを読んでください。アイテムごとの理由 Code が、どのアイテムがなぜ失敗したかを正確に教えてくれます。

意味

DynamoDB のトランザクションはオール・オア・ナッシングです。いずれかのアイテムの条件が失敗するか、キャパシティを超過するか、2つのトランザクションが衝突すると、全体がキャンセルされ、何も書き込まれません。トップレベルのメッセージは一般的なものです。

TransactionCanceledException: Transaction cancelled, please refer cancellation reasons for specific reasons [ConditionalCheckFailed, None, TransactionConflict]

角括弧のリストは 位置対応 です — トランザクション内のアイテムごとに1エントリ、順番どおりに並びます。DynamoDB はこの例外を HTTP ステータス 400 で返し、AWS SDK は自動では リトライしません — 理由コードごとに、リトライが妥当かどうかはあなたのコードが決めます。

発生する理由(理由コード)

  • ConditionalCheckFailed — そのアイテムの ConditionExpression が false と評価された(ConditionalCheckFailedException を参照)。
  • TransactionConflict — 別の並行トランザクション(または書き込み)が同じアイテムを操作している。バックオフしてリトライしましょう。
  • ProvisionedThroughputExceeded — そのアイテムのテーブル/インデックスがキャパシティを使い切った。
  • ThrottlingError — テーブルまたはインデックス(典型的にはオンデマンドで、DynamoDB がまだスケール中)が書き込みをスロットリングした。バックオフしてリトライしましょう。
  • ValidationError — そのアイテムが不正な形式だった(無効なパラメータ値、ドキュメントパス、オペランド型、サイズ超過など)。
  • ItemCollectionSizeLimitExceeded — LSI のアイテムコレクションが 10 GB に達した。
  • None — そのアイテムには問題がなかった。失敗はリストの別の場所にあります。

これがドキュメント化されたコードの全集合です。重複したアイテムキー(2つのアクションが同じアイテムを対象にする)はキャンセルコードではないことに注意してください — DynamoDB はそのリクエストを事前に ValidationException として拒否します。

修正方法

  1. メッセージだけでなく、エラーから CancellationReasons を読みます。 各エントリをインデックスで入力アイテムに対応づけましょう。
  2. コードで分岐します: ConditionalCheckFailed → ビジネスロジック、TransactionConflict/ThrottlingError/ProvisionedThroughputExceeded → 指数バックオフでリトライ、ValidationError → リクエストを修正。
  3. 重複キーを避けます — 1つのトランザクションが同じアイテムに2回触れることはできません。

アイテムを手作業で編集していますか? DynoTable のステージングエリアは編集を1つのトランザクション書き込みにまとめ、コミット前にすべてのアイテムを確認させてくれます — リクエストを手で組み立てずに、同じオール・オア・ナッシングのセマンティクスが得られます。

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 の中の1つのアイテムが失敗しました — 条件チェック、スループット/スロットリングの上限、あるいは別の並行トランザクションとの競合です。そのため DynamoDB はトランザクション全体をロールバックし、何も書き込みませんでした。アイテムごとの理由は CancellationReasons 配列にあります。

トランザクション内のどのアイテムが失敗したかを見つけるには? TransactionCanceledException の CancellationReasons 配列を読みます。入力アイテムごとに1エントリが同じ順序で並んでおり、Code が「None」でないエントリが、キャンセルの原因となったアイテムです。

再現方法

1つのトランザクション内の2つの書き込みで、2つ目は成立しえない条件でガードします。トランザクション全体がロールバックされ、アクションごとの判定が 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 を報告します — それ自体は失敗しておらず、隣のアクションが失敗したためにロールバックされたのです。実際の犯人を特定できるのは CodeNone でないエントリだけで、そのインデックスは自分の TransactItems 配列における問題のアクションのインデックスです。

関連するエラー

参考資料

最終検証日 2026-07-13、上記にリンクした公式 AWS ドキュメントに照らして確認しました。

2026-07-26 に DynamoDB Local 2.x と AWS SDK for JavaScript v3.1095.0 で再現しました — 上記の出力はそのままの逐語です。

Console なしで DynamoDB を扱う

DynamoDB では実行できない本物の SQL(JOINs、GROUP BY、集計)を実行する高速な DynamoDB デスクトップクライアント。ビジュアル編集と、あなた自身の Bedrock キーで動く AI エージェントを備えています。

30日間無料トライアル、クレジットカード不要 — その後は期限のない Free プラン。