Bulk Put Items in Amazon DynamoDB - Loading S3 Data into an Existing Table, Per-Item Conditions, and the Report

First Published:
Last Updated:

Amazon DynamoDB's bulk put items feature allows you to read files from Amazon S3 and write those items into an existing DynamoDB table. This feature became generally available on November 5, 2026. It is a separate function from Import from Amazon S3, which creates new tables, and allows you to give each record of the input its own condition expression. Rows that do not meet the specified conditions will be skipped.

This article details which of five outcomes one row of the input has (written, overwritten, skipped, an error, or not read), and where each outcome is tracked (or not tracked). It also describes what remains in the table if the operation is interrupted, and from which point you would need to resume the process.

To summarize, rows that are skipped due to the conditional checks are not counted as failures. If the output report does not include the CONDITION_CHECK_FAILURE type, no record or count of those skipped rows remains. Rows that have been written are not rolled back, even if the operation fails or is canceled.

This article reviewed the documentation on November 11, 2026 (Japan Standard Time) and, on the same day, tested five scenarios on a small table in the us-east-1 Region. The results are presented as observations in Chapter 10, separate from the statements in the documentation. Pricing and speed comparisons between the performance tiers are not included.

Related articles on this site:

Table of Contents

  1. 1. Scope and Assumptions
  2. 2. How to Read the Tables
  3. 3. Where Bulk Put Items Fits
  4. 4. Input Format and Per-Record Conditions
  5. 5. Where One Record Goes
  6. 6. What Is Recorded and What Is Not
  7. 7. How an Operation Ends and What Stays in the Table
  8. 8. What Happens Around the Table
  9. 9. MaxWriteRequestUnits and Quotas
  10. 10. Observations on a Small Table
  11. 11. Where the Sources Disagree and What They Do Not Say
  12. 12. Failure Modes
  13. 13. Frequently Asked Questions About DynamoDB Bulk Put Items
  14. 14. Summary
  15. 15. References

1. Scope and Assumptions

This chapter first defines the intended audience, the scope of this article, the materials reviewed, and the terminology used. The following ten points outline the key conclusions.

  • Bulk put items writes data to an existing table. It is a separate function from Import from Amazon S3 and does not create new tables. The writes run on a separate path and do not use the table's read or write capacity (Chapter 3).
  • Input data must be in DynamoDB JSON or Amazon Ion format, with one record per line. CSV is not supported. A condition expression is written per record. Records without a condition overwrite the existing item with the same key (Chapter 4).
  • For each record in the input, there are five possible outcomes: it is written, overwritten, skipped by a condition, results in an error, or is not read. Only rows that result in an error are counted in the FailedItemCount (Chapter 5).
  • Rows skipped by a condition are recorded only if the output report types include CONDITION_CHECK_FAILURE. Otherwise, no record or count of them remains (Chapter 6).
  • There are six status values, four of which represent end states. COMPLETED indicates that the FailedItemCount is zero, but does not necessarily mean that all rows have been written (Section 7.1).
  • Rows that are written will remain in the table, even if the operation fails (FAILED) or is canceled (CANCELLED). They cannot be reverted (Sections 7.3 and 7.4).
  • Following an internal failover, the same record may be written twice. The second write will also apply the record's condition expression. If you put a version condition on every row, you can prevent an older value from overwriting a newer one (Section 7.6).
  • You cannot initiate a bulk put items operation on tables that belong to a global table (Section 8.7).
  • MaxWriteRequestUnits defines the maximum write speed for this operation and is independent of the table's capacity settings. The minimum value is 1,024. On-demand tables have a parameter with the same name for the table's own limit (Chapter 9).
  • When testing with a small table, an operation that completed (COMPLETED) with a FailedItemCount of zero still had five out of seven rows skipped by a condition. Because that report was not requested, the output was only the manifest (Section 10.3, Observation).

1.1 Intended Audience

This article is intended for the following readers:

  • Developers designing how to load data from S3 into existing DynamoDB tables in a production environment.
  • Operations personnel considering transitioning daily delta updates or bulk migration loads from BatchWriteItem loops or custom pipelines to bulk put items.
  • Individuals responsible for defining procedures to verify which rows have been written after a data transfer.

This article assumes readers are considering the following points, and each point is validated in the article's content:

  • If the number of failures is 0, then all input rows have been written.
  • If an operation fails, the written rows are rolled back.
  • The number of processed items, ProcessedItemCount, represents the number of rows written.
  • Writing a condition expression on one row makes the entire file insert-only.
  • Using the same ClientToken ensures that re-running the process will not result in duplicate writes.

1.2 What This Article Covers and What It Does Not

This article addresses the behavior when writing to existing tables, row-level conditions, where each row goes and where it is recorded, status values and how an operation stops, re-runs and idempotency, the effects around the table, the cases where it cannot be used, MaxWriteRequestUnits and quotas, IAM actions, discrepancies between the sources, and observations on a small table.

This article does not cover:


Chapter 6 of this site's DynamoDB Key Design Dictionary states in its table, for Import from Amazon S3, that a new table is created and that data cannot be imported into an existing table. As of November 11, 2026, the Import from S3 page still states the same. The bulk put items covered in this article is a different feature.

1.3 Date of Review and Materials Reviewed

This article reviewed the following materials on November 11, 2026 (Japan Standard Time). Throughout the text, the English names in parentheses are used.

  • Amazon DynamoDB Developer Guide: The "Working with bulk put items" section (how-it-works page).
  • Same guide: the page on performance tiers (performance tiers page), the page on input formats (input formats page), the page on running an operation (running page), the page on output and reconciliation (output page), the page on considerations, quotas, and permissions (considerations page), and the page on best practices (best practices page).
  • Same guide: The "Bulk put items" section of the "Quotas in Amazon DynamoDB" page (quotas page).
  • Same guide: The "Import from Amazon S3" section (Import from S3 page).
  • Amazon DynamoDB API Reference: The pages for StartBulkPutItems, DescribeBulkOperation, ListBulkOperations, and CancelBulkOperation (API reference), as well as the pages for BatchWriteItem, PutItem, and UpdateTable (for comparison).
  • AWS CLI Command Reference: The page for start-bulk-put-items (CLI reference).
  • AWS What's New: The announcement from November 5, 2026 (What's New post).
  • AWS Database Blog: The article "Introducing bulk put items for Amazon DynamoDB" (launch blog post).
  • AWS Machine-Readable Service Reference: The DynamoDB JSON (service reference).

All materials were reviewed in their original, raw format (obtained via curl). As of November 11, 2026, the DynamoDB page in the Service Authorization Reference redirects to the table of contents page. IAM actions were reviewed in the table on the considerations page and in the service reference.

1.4 Terms, and Different Things with the Same Spelling

This article will consistently use the following terms:

  • Operation: A single bulk put items process initiated by StartBulkPutItems. The documentation also calls it a bulk operation.
  • Record: A single line from the input file, containing an Item and optional condition fields.
  • Item: A DynamoDB item as it appears in the table.
  • Condition Expression: The ConditionExpression written for each record. It follows the same syntax as PutItem.
  • Skip: When a condition expression evaluates to false, resulting in the record not being written.
  • Report: A file written to the output location, containing a list of items that were not written. There are two types: ERROR and CONDITION_CHECK_FAILURE.
  • Manifest: A file written to the output location, detailing the processing status of each object from the input. The running page also calls it a completion manifest.

The materials that this article reviewed contain different things with the same spelling:

  • MaxWriteRequestUnits: In the context of bulk put items, this refers to the maximum write speed for a single operation. Similarly, on-demand tables also have a parameter with the same name, representing the maximum number of write units for the table in on-demand capacity mode. The command examples in Chapter 2 of the Amazon DynamoDB Capacity and Global Tables Guide refer to the latter (Section 9.2).
  • Import: Import from Amazon S3 refers to the functionality for creating new tables. The launch blog post also calls a single run of bulk put items an "import." However, this article uses the term "operation" to refer to a bulk put items execution, reserving the term "import" specifically for Import from Amazon S3.
  • Report: In this article, "report" refers only to the two file types specified by OutputType. The manifest is not included in the report.
  • Condition: In this article, "condition" refers only to the ConditionExpression for each record. Conditions such as whether a table is in the ACTIVE state are referred to as table states.
  • Bulk and Batch: Bulk put items is distinct from the "batch" used in the BatchWriteItem API. This article uses the term "batch" only in reference to the BatchWriteItem API.

2. How to Read the Tables

This chapter defines the terminology used in the tables in this article, specifically the terms for the state of the sources, and how this article writes verification dates and dates.

2.1 Terms for the State of the Sources

This article uses seven terms to describe the state of the documentation. These terms, including their English spellings, will also be used in the tables.

  • Stated: The documentation contains a statement regarding the matter.
  • Stated as not supported: The documentation explicitly states that the matter is not supported or cannot be used.
  • Documentation does not list: While a list or table exists, the specific item is not included. This does not necessarily indicate that the matter is unsupported or unavailable.
  • No statement found: Despite searching using different search terms and examining different categories of documentation (as described in Section 1.3), no relevant statement could be found. This does not necessarily indicate that the matter is absent or does not occur.
  • Sources disagree: The documentation from two different sources provides conflicting statements regarding the same matter. This includes cases where the statements directly contradict each other, as well as cases where the scope, strength, or subject matter differs, and the text alone does not settle which one applies. This article presents both statements and their sources without designating either as incorrect.
  • Inference: This represents an inference made by this article, and is not a statement found in any of the documentation. This article says in the same sentence that it is an inference.
  • Observation: This is based on observations made during testing (as described in Chapter 10) and is not a commitment made by the documentation. This article will not override statements found in the documentation with observations.

This article distinguishes between "Stated as not supported" and "No statement found." The former refers to a statement in the documentation, while the latter indicates that this article was unable to find a relevant statement.

This article does not call two statements that differ only in what they count "Sources disagree." For example, a statement listing six status values and another listing four end states simply differ in scope (Section 11.1).

2.2 How This Article Writes Verification Dates and Dates

The verification date for this article is November 11, 2026 (Japan Standard Time). The general availability of bulk put items began on November 5, 2026, and the verification date is six days after that. Pages may be updated after the verification date. In particular, the FailureCode table, quota information, the Regions where Accelerated is available, and the handling of global tables may be subject to change.

This article writes the date of the observations in Chapter 10 in Japan Standard Time, and writes every date with its year.

3. Where Bulk Put Items Fits

This chapter explains how bulk put items differs from the other ways of writing.

3.1 A Separate Path That Writes into an Existing Table

The how-it-works page describes bulk put items as follows:

Bulk put items loads data from Amazon Simple Storage Service (Amazon S3) into an existing Amazon DynamoDB table. The writes run on a separate path and consume none of the table's read or write capacity, so your application traffic sees no impact from these bulk put items.

The same page states that items become available for reading as they are written. The same page also states the difference from Import from Amazon S3 in one sentence.

Import from Amazon S3 creates a new table from data in Amazon S3, while bulk put items writes into a table that already exists.

The operation is asynchronous. StartBulkPutItems immediately returns the ARN of the operation. DynamoDB then reads the input objects, writes each item to the table, handles retries and exceptions, and writes a report to the designated output location (as described on the how-it-works page).

The mandatory inputs required to initiate the operation are as follows (see the running page and API reference):

  • TableName: The name or ARN of the table to which data will be written.
  • InputS3Configuration: The location of the input data. S3Bucket and InputFormat are required; S3BucketOwner, S3KeyPrefix, and InputCompressionType are optional.
  • OutputS3Configuration: The location for the output data. S3Bucket and OutputType are required.

Specifying the output location is essential. The running page states that the output configuration is mandatory. The optional parameters are PerformanceTier, MaxWriteRequestUnits, and ClientToken.

3.2 Differences from Other Ways of Writing

The following table lists ways of writing S3 data and large numbers of items into DynamoDB. All columns are based on the information in Section 1.3. The BatchWriteItem and PutItem rows are based on their respective API reference pages.

MethodDestinationInputPer-Item ConditionsResult Logging
Bulk Put ItemsExisting TableS3 DynamoDB JSON or Amazon IonYes. ConditionExpression per recordS3 reports and manifests, count from DescribeBulkOperation
Import from Amazon S3New Table. Created during import initiationS3 CSV, DynamoDB JSON, Amazon IonDocumentation does not listNot covered in this article
BatchWriteItemExisting TableAPI RequestNo. Conditions cannot be applied to individual Put and Delete requestsUnprocessed requests are returned in the response's UnprocessedItems
PutItemExisting TableAPI RequestYes. ConditionExpression per requestSuccess or failure is returned in the response

The Import from S3 page states that it cannot be used to write data to existing tables.

Import into existing tables is not currently supported by this feature.

This passage describes the Import from Amazon S3 feature. Since November 5, 2026, bulk put items has been available as a way to write S3 data to existing tables.

3.3 Small Inputs Suit the Existing APIs

The launch blog post states that the initial few minutes are used for preparation, during which the counters do not move. It further suggests that if you need to write only a few items within a few seconds, PutItem and BatchWriteItem are suitable options.

For delivering a handful of items in seconds, PutItem and BatchWriteItem remain the right tools.

Bulk put items writes complete items. The launch blog post recommends using UpdateItem for changes to individual attributes. There is no way to modify only a portion of an existing item using bulk put items. A record without a condition replaces the whole item with the same key (see Section 4.3).

Global tables do not support bulk put items. The considerations page recommends using BatchWriteItem or PutItem in such cases (see Section 8.7).

4. Input Format and Per-Record Conditions

This chapter describes the format of the input file and explains how condition expressions are evaluated for each record.

4.1 Formats and Compression

The InputFormat value can be either DYNAMODB_JSON or ION (see the input formats page and API reference). DYNAMODB_JSON is a JSON Lines format where each line contains a single JSON object, representing DynamoDB's typed JSON. No line breaks are allowed within a single record. ION is in Amazon Ion text format, with each record represented as an Ion struct, separated by line breaks. There are no CSV options available.

The InputCompressionType value can be GZIP, ZSTD, or NONE. The CLI reference states that if no value is specified, it defaults to NONE.

The input can consist of a single S3 object, or multiple objects with the same key prefix. If S3KeyPrefix is specified, DynamoDB will read all objects under that prefix. The input formats page states that all objects under the same prefix must use the same format and the same compression type.

You cannot mix DynamoDB JSON and Ion objects, or mix compressed and uncompressed objects, in a single bulk put items operation.

4.2 Fields in One Record

A single record can have only four top-level fields (see the input formats page):

  • Item: The item to be written. Required.
  • ConditionExpression: The condition expression. Optional.
  • ExpressionAttributeNames: Replacements for attribute names in the condition expression. Optional.
  • ExpressionAttributeValues: Replacements for values in the condition expression. Optional.

A record with any other top-level field causes a validation error that stops the reading of that object (see Section 5.2). The following example demonstrates a DynamoDB JSON input, where the first line has no condition, the second line has an insert-only condition, and the third line has a version condition.

{"Item":{"id":{"S":"order-001"},"status":{"S":"PENDING"},"version":{"N":"1"}}}
{"Item":{"id":{"S":"order-002"},"status":{"S":"PENDING"},"version":{"N":"1"}},"ConditionExpression":"attribute_not_exists(id)"}
{"Item":{"id":{"S":"order-003"},"status":{"S":"SHIPPED"},"version":{"N":"4"}},"ConditionExpression":"attribute_not_exists(#v) OR #v < :new","ExpressionAttributeNames":{"#v":"version"},"ExpressionAttributeValues":{":new":{"N":"4"}}}

4.3 How Condition Expressions Are Evaluated

Condition expressions use the same syntax, operators, and functions as those used in PutItem (see the how-it-works page). A record is written only when the condition expression evaluates to true; otherwise, the record is skipped. The input formats page details the evaluation results, categorized into four outcomes:

RecordResult
No condition expressionThe item is written unconditionally. If an item with the same primary key already exists, it will be overwritten.
attribute_not_exists(pk)Insert-only for that record. It is written only when there is no existing item with the same primary key.
Version-based condition (e.g., #v = :expected)The record is written based on a comparison of the version attribute. To write both new items and new versions, use attribute_not_exists(#v) OR #v < :new.
Condition not metThe item is skipped. It is recorded only when a CONDITION_CHECK_FAILURE report is requested.

Records without conditions are written in their entirety. Attributes present in the existing item but not included in the record's Item will be lost after the overwrite. In the setup in Chapter 10, when a record without a condition overwrote an existing item, the attribute category that was previously present on the item was removed (Observation).

No limit on the length or the number of operands of condition expressions specific to bulk put items was found in the materials in Section 1.3 (No statement found). The output page notes that if the operands in a condition expression are invalid, the record may result in an ERROR.

4.4 Without a Condition on Every Record, a File Is Not Insert-Only

Conditions are specified for each record. There are no fields for applying conditions to the entire file or the entire operation. The input formats page states that to make the entire file insert-only, you must write a condition expression on every record.

Because conditions are per-item, you must include a ConditionExpression on every record if you want put-if-not-exists behavior across the entire file.

The same page states that if you generate input in an ETL pipeline, you add ConditionExpression to the record template, and that existing files without conditions are reprocessed to add the condition before the operation starts. A record without a condition silently overwrites the existing item.

5. Where One Record Goes

This chapter shows where one input record goes and where it is counted.

5.1 Five Destinations

A single input record can have one of five possible destinations.

Where One Input Record Goes in a Bulk Put Items Operation
Where One Input Record Goes in a Bulk Put Items Operation
Figure 1 illustrates the branching paths based on four questions: whether the record's boundary can be found, whether the record passes validation, whether the record has a condition expression, and whether the condition expression is true. The following table details, for each destination, how the table item is affected, where the record is counted, and where it is recorded.

DestinationTable ItemsProcessedItemCountFailedItemCountReportStream Record
Written. New KeyNewly writtenCountedNot countedNo reportRecord generated
Overwritten. No condition, or condition is trueCompletely replacedCountedNot countedNo reportRecord generated
Skipped based on conditionUnchangedCountedNot countedReport generated only when CONDITION_CHECK_FAILURE is requestedNo record generated
Error. Validation error, etc.UnchangedCountedCountedReport generated when ERROR is requestedNo record generated
Not read. After reading of the object stoppedUnchangedDocumentation does not listDocumentation does not listNo reportNo record generated

ProcessedItemCount represents the number of records read. This count includes records that failed validation or were skipped due to conditions, but does not represent the number of items written.

ProcessedItemCount – The number of input records read so far, including records that failed validation or a condition check. This is a count of records read, not items written.

FailedItemCount represents the number of items that failed for deterministic reasons. Records skipped based on a condition are not included in this count.

FailedItemCount – The number of items that failed for deterministic reasons, such as validation errors. Condition-check failures are not included in this count.

The stream column is based on the text in the considerations page. In tables with DynamoDB Streams or Kinesis Data Streams enabled, every bulk write produces a stream record. However, items skipped based on a condition do not generate a record (see Section 8.1). This article infers (Inference) that error rows and rows that are not read are not written to the table and therefore do not produce stream records. In the setup in Chapter 10, error rows and rows that were not read did not have corresponding records (Observation).

The statement that unread rows are not included in the ProcessedItemCount is not found in the material in Section 1.3. In the setup in Chapter 10, the two rows after a truncated record were not included in either the ProcessedItemCount or the FailedItemCount (Observation, Section 10.4).

5.2 Errors That Fail One Record and Errors That Stop an Object

Errors can occur in two ways: those that fail only that one record, and those that prevent the rest of an object from being read (see the input formats page).

Validation errors that apply to one complete record will include an itemIndex in the report row and will not prevent the rest of the object from being processed. The output page provides examples, including items exceeding the maximum allowed size and items missing required key attributes.

Errors that prevent DynamoDB from locating the next record boundary stop the reading of that object. The input formats page lists examples such as malformed or truncated JSON or Ion, errors in the record structure, missing or duplicate Item fields, unknown top-level fields, invalid DynamoDB values, invalid UTF-8 encoding, input exceeding the parser's nesting limit, records exceeding the parser's read limit, decompression errors, compression mismatches, and some S3 object-read errors.

When one of these errors occurs, DynamoDB produces one error result and stops reading that Amazon S3 object. Other input objects can continue.

In these cases, the ERROR report row will include itemLocation.inputSourceArn and errorMessages, but will not include itemLocation.itemIndex. The manifest will mark the object as PARTIALLY_PROCESSED and will document the range of records that were processed in the processedRanges field.

5.3 Unread Records and How the Operation Ends

When reading of an object stops, there are two possible end states for the operation (input formats page).

  • If DynamoDB cannot verify that it has read all the bytes of the stored input, the operation will end with a status of FAILED, and the FailureCode will be ValidationException.
  • In some cases, if all stored bytes have been read before an error is encountered, the operation may end with a status of COMPLETED_WITH_ERRORS. In this scenario, ProcessedInputBytes will be equal to TotalInputBytes.

The best practices page notes that a single record that DynamoDB cannot parse can stop the reading of the rest of that object, and can end the whole operation FAILED. It recommends running validation tests with a sample of the input data before initiating large operations.

Unread records do not appear as individual rows in the ERROR report. Examining processedRanges in the manifest identifies the range of unread data. The decision on which records to correct and which to resubmit should be based on the final status, the ERROR report, and the manifest (input formats page).

6. What Is Recorded and What Is Not

This chapter outlines the locations where operational results are recorded, and specifies what information is included and what is not.

6.1 The Two Report Types

OutputType is an array that contains one or both of the following values (running page, output page).

OutputType ValueItems Included
ERRORItems that failed for deterministic reasons, such as validation errors.
CONDITION_CHECK_FAILUREItems for which the condition expression for that record was not met.

For inputs that use condition expressions, the input formats page states that you request CONDITION_CHECK_FAILURE. If it is not requested, records and counts of skipped items will not be retained.

When your input uses condition expressions, request CONDITION_CHECK_FAILURE so skipped items are reported, because without it DynamoDB keeps no record or count of them.

The number of skipped items will not appear as a separate count in the response from DescribeBulkOperation either. The output page states this in an Important note.

Condition-check failures are not exposed as a separate count in the DescribeBulkOperation response.

Combining these two points, this article infers (Inference) that if an operation does not request CONDITION_CHECK_FAILURE, neither which records were skipped nor how many were skipped can be determined from the operation's records. They can be found only by comparing the current items in the table with the input.

6.2 What the Counts Mean

The response from DescribeBulkOperation returns progress and counts in the following fields (running page, output page).

FieldMeaning
ProcessedItemCountThe number of records read. This includes records that failed due to validation or conditions. This is not the number of items written.
FailedItemCountThe number of items that failed for deterministic reasons. This does not include items skipped due to conditions.
ProcessedInputBytesThe total number of bytes read and processed from S3 so far.
TotalInputBytesThe total size of the input objects. This value is not included in the response until it is calculated during the initial input validation.

This table has no field for the number of items written. The API reference for DescribeBulkOperation also does not list a field that returns the number of items written. The running page states that the progress fields update periodically and are not live counters, and that you do not rely on a fixed refresh interval.

6.3 The Manifest

DynamoDB, in addition to the report, writes the status of processing for each input object to a manifest file (output page). The manifest is an uncompressed JSON Lines file, with one line per input object. Each line contains the following fields: inputSourceArn, fileProcessingStatus, processedRanges, and etag. The processedRanges field contains an array of ranges, represented as [start, end] pairs, indicating the records that were processed.

The fileProcessingStatus field can take one of four values:

ValueMeaning
FULLY_PROCESSEDAll items for this object have been processed.
PARTIALLY_PROCESSEDNot all items have been processed. processedRanges may be empty, for example, when the first record cannot be parsed.
NOT_PROCESSEDThe operation ended before it reached this object, due to cancellation, failure, or timeout.
NOT_AVAILABLEIt was not possible to determine how much of the object was processed. No range is written. Treat the object as not fully processed.

The manifest is written after the operation ends. The output page states that NOT_PROCESSED never means that the object is still waiting to be processed.

The manifest indicates how much of each input object was processed. Whether individual items failed or were skipped based on a condition is indicated in the report (output page), not in the manifest. This article infers (Inference) that the manifest does not show that a record in the processed range was written. The range may include records that were skipped due to a condition or records that resulted in an error. In the setup in Chapter 10, even when four out of nine records were skipped or resulted in an error, the manifest range was [[0, 8]] (Observation).

If the operation cannot write the manifest to the output location, the operation will end with a status of FAILED, even if all items have been written.

6.4 Where the Output Goes

The manifest is written to the following path (output page).

s3://output-bucket/output-prefix/AWSDynamoDB/BulkOperation/account-id:operation-id/manifest-files.json

Reports are written to directories specific to each internal job. For example, the ERROR report can be found at the following path, while the CONDITION_CHECK_FAILURE report is located in the condition-check-failures/ directory at the same level.

output-prefix/AWSDynamoDB/BulkOperation/account-id:operation-id-n/output/errors/output-NNNNN.json.gz

The report files are gzipped JSON Lines files. Because DynamoDB closes each file at 200 MiB and starts a new one, report files can appear while an operation is still IN_PROGRESS. A file for a requested report type is written only if at least one item belongs to that type (output page).

Each row in a report contains itemLocation and errorMessages. itemLocation includes inputSourceArn and itemIndex. However, if a record is truncated and the system is unable to read the remainder of the object, the itemIndex may be missing. For CONDITION_CHECK_FAILURE rows, both the newImage of the item that the operation tried to write and the oldImage of the item as it existed in the table are included. Consequently, condition reports can be larger than the input they describe. ERROR rows may not include a newImage if the item exceeded the maximum allowed size or for a record with an invalid condition operand (output page).

In some cases, nothing is written to the output. The output page lists the following two cases:

  • The S3BucketOwner does not match the owner of the output bucket, causing the operation to fail and preventing both the report and the manifest from being written.
  • If another operation is running on the same table, a ResourceInUseException may cause the operation to fail, preventing both the manifest and the report from being written.

6.5 Reconciliation Procedure

The output page describes a procedure for understanding the overall results. This article lists its first two steps as the following four items:

  1. Call DescribeBulkOperation until the status reaches COMPLETED, COMPLETED_WITH_ERRORS, CANCELLED, or FAILED, recording the ProcessedItemCount and FailedItemCount.
  2. List all objects that begin with output-prefix/AWSDynamoDB/BulkOperation/account-id:operation-id. This will return the manifest file and all report files. If no manifest file is found, check the FailureCode.
  3. Read the manifest file, verifying the fileProcessingStatus and processedRanges for each input object, and confirming that the etag matches the object's own etag.
  4. Read all of the report files.

The output page states that this method, combining analysis of the API count and the S3 report files, provides the most accurate reconciliation. The API provides an overall summary, while the S3 reports provide details for each individual item.

For operations that did not request CONDITION_CHECK_FAILURE, the files read in the fourth item of this list do not contain any skipped items. This article infers (Inference) that this procedure cannot count the skipped items of such an operation.

The input formats page notes that re-run or resumed operations may report a condition mismatch for an item that the operation itself wrote earlier. To tell this apart from a mismatch with existing data, compare the existing item in the report with the item you supplied. If they are equal, the operation wrote that item, and the mismatch is expected.

6.6 Permissions for Reading the Results

DynamoDB uses the credentials of the IAM principal that called StartBulkPutItems to read the input and write the report and manifest (output page). It is not necessary to grant access to DynamoDB's service principal. The input and output buckets can reside in different AWS accounts, and the input bucket can even be in a different AWS Region than the table.

To verify the results, the principal that checks them needs s3:ListBucket and s3:GetObject permissions on the output bucket. The output page states that the example write policy does not grant these read permissions, and that they are granted in a separate statement to the principal that checks the results. The bulk put items operation itself does not require these read permissions.

6.7 BulkOperationUsage

The response from DescribeBulkOperation includes a BulkOperationUsage field, which returns the number of bytes written for each destination (output page). This field contains values for tables, global secondary indexes, local secondary indexes, and vector indexes. Bulk operations do not use the ConsumedCapacity field, which is returned by item-level operations such as PutItem.

BulkOperationUsage represents the number of bytes written for each destination, and does not indicate the number of items written. This article does not derive the number of items written from this field. The output page states that items that reach the table and fail a condition check are metered as table writes. Therefore, the value for the table in this field can include bytes for skipped items (Stated). In the setup in Chapter 10, the value for the table after R1 was 7,168 bytes, which this article reads as 7 × 1,024 bytes for the five written rows and the two skipped rows (Observation, Inference).

7. How an Operation Ends and What Stays in the Table

This chapter describes the status values, the reasons for failure, cancellation, and re-runs.

7.1 Six Status Values, Four End States

There are six BulkOperationStatus values. The running page and the Valid Values of the CancelBulkOperation page in the API reference list the same six.

ValueEnd State?Meaning on the Running Page
IN_PROGRESSNoReading input and writing items.
COMPLETEDYesAll input has been read, and FailedItemCount is 0. Some items may have been skipped based on conditions.
COMPLETED_WITH_ERRORSYesAll input has been read, but FailedItemCount is greater than 0. View the ERROR report.
CANCELLINGNoApplying the cancellation request.
CANCELLEDYesThe operation stopped due to the cancellation request. The written items remain in the table. The FailureCode is RequestCancelled.
FAILEDYesThe operation could not be completed. View the FailureCode.

The definition of COMPLETED states in the same sentence that some items may have been skipped based on conditions.

COMPLETED – All input was read and FailedItemCount is 0. Items can still have failed a condition check.

COMPLETED indicates that the number of failures is 0. It does not necessarily mean that all input records have been written. The definition of COMPLETED_WITH_ERRORS also says that all input was read. The input formats page states that an operation can end COMPLETED_WITH_ERRORS when DynamoDB read all stored bytes before detecting an error, so records after a broken record can remain unread (Section 5.3).

Figure 2 illustrates the state transitions and, for each end state, what remains in the table, report, and manifest.

How a Bulk Put Items Operation Ends and What Stays Written
How a Bulk Put Items Operation Ends and What Stays Written
Regarding CANCELLED, the running page states that CANCELLED does not mean that data is missing, and that the manifest records what was processed.

7.2 FailureCode

A FAILED operation indicates the reason with FailureCode. The table on the running page lists the following values (as of November 11, 2026).

FailureCodeCauseWhat the running page says to do
TimeoutExceeded the maximum processing time.Resubmit the remainder from the manifest.
ValidationExceptionAn error occurred while reading the input object, and it was not possible to verify that all saved bytes had been read.Fix the record, then resubmit it together with the records outside processedRanges.
InputObjectTooLargeThe input object exceeded 5 GB.Split the object.
S3ObjectsCountLimitExceededThe number of input objects exceeded 50,000.Reduce the number of objects or request an increase in the quota.
SizeLimitExceededThe total input size exceeded the limit for a single request. Standard: 100 GB, Accelerated: 1 TB.Split the input or use Accelerated mode.
ObjectModifiedInS3DuringImportThe input object was modified while processing.Do not modify the input object while processing.
KmsAccessDeniedException, KmsDisabledException, KmsNotFoundException, KmsInvalidKeyUsageException, KmsInvalidStateExceptionUnable to use the AWS KMS key for the table or S3 object.Verify the key's status and the permissions of the caller.
S3AccessDeniedAccess to the S3 input or output location was denied. This may occur when the S3BucketOwner does not match the bucket owner.Verify the caller's S3 permissions, the bucket policy, and the S3BucketOwner.
ResourceInUseExceptionAnother operation was already in progress on the same table.Wait for the current operation to complete and then retry.
DynamoDBResourceNotFoundExceptionThe table could not be found or accessed.Verify the table name and status.
DynamoDBAccessDeniedExceptionThe caller lost permission to write to the table.Restore dynamodb:BulkPutItems on the table, then resubmit the remainder.
DynamoDBItemCollectionSizeLimitExceededExceptionFor tables with local secondary indexes, the item collection exceeded the size limit.Reduce the amount of data for the partition key value.

Regarding timeouts, the running page states that Timeout is an expected outcome, not a fault, for a very large input or for an operation whose rate is capped with MaxWriteRequestUnits. The maximum processing time is not listed in the running page or in the other materials in Section 1.3 (Documentation does not list).

If the manifest cannot be written to the output location, the operation will fail, even if every item was written.

If DynamoDB cannot output the completion manifest to the output location, the operation ends FAILED even if every item was written.

The failure message in this scenario begins with Manifest is not available., and the FailureCode indicates the underlying cause. The running page instructs users to verify S3 and AWS KMS permissions for the output prefix, and to compare the table and input data to determine what was actually written.

Errors related to S3BucketOwner are only identified after the operation has begun. The considerations page states:

If S3BucketOwner is wrong, StartBulkPutItems still returns an operation ARN. DynamoDB can write items to the table before the operation fails with S3AccessDenied, and it outputs no report or manifest.

A returned ARN does not indicate that the operation will succeed. This article infers (Inference) that in a FAILED operation where neither a report nor a manifest is available, the only way to determine which items were written is by comparing the table and input data.

7.3 Written Items Are Not Rolled Back

Bulk put items has no mechanism to undo written items. The running page states the following in its section on cancellation:

Items already written before cancellation are not rolled back. They remain in the table and are immediately readable.

Even if the operation fails (FAILED), the same applies. The running page states that, in the case of a Timeout or when the manifest cannot be written, any previously written items will remain in the table. The considerations page states that if the caller loses dynamodb:BulkPutItems permissions or AWS KMS access to the table's customer managed key during execution, the operation will fail (FAILED), and any previously written items will remain in the table.

Therefore, after a FAILED or CANCELLED operation, the table may end up with only a portion of the intended data written. The launch blog post states that a canceled operation may leave the table partially updated.

7.4 Cancellation

CancelBulkOperation is used to asynchronously cancel an ongoing operation (API reference). The response status will be CANCELLING, and the operation will transition from CANCELLING to CANCELLED. The API reference specifies that cancellation will not delete any data that has already been written.

The running page indicates that while the status is CANCELLING, the progress counters can be lower than the final values. It advises users to wait for the status to reach CANCELLED before verifying the results. In the manifest, a partly processed object is PARTIALLY_PROCESSED, and records outside processedRanges were not processed. The running page instructs users to resubmit these records, along with any records that have been corrected from ERROR reports.

7.5 ClientToken and Deliberate Re-runs

ClientToken is an idempotency token for the start request. The API reference states:

During the 8 hours after the initial request, repeated requests that use the same token and parameters return the same bulk operation. If a request reuses the token with different parameters, DynamoDB returns an IdempotentParameterMismatchException.

If a token is not provided, the AWS SDK automatically generates one. The best practices page recommends providing a ClientToken when retrying a start request to prevent the operation from being initiated multiple times.

The purpose of ClientToken is to prevent the same start request from triggering the operation more than once. It does not prevent re-running the same file with a new start request. The launch blog post states that a deliberate re-run is a new operation.

A deliberate re-run, however, is a new operation, and only your conditions stop it from overwriting data your application wrote in the meantime.

What keeps a re-run from overwriting existing items is each record's condition expression. The launch blog post suggests defining conditions to ensure that a second execution of the same file does not result in any changes. It recommends using attribute_not_exists for purely inserting new data and version comparisons for updates.

7.6 When the Same Record Is Written Twice, and Version Conditions

Within a single operation, the same record may sometimes be written twice. The considerations page states:

During an operation, DynamoDB can write some records a second time after an internal failover. Each repeated write uses the record's condition expression, so a version guard on every record prevents a repeated write from replacing newer data.

The same page states that if an application writes to the same keys during an operation, a repeated write of a record without a condition can overwrite a more recent write from the application. To protect such keys, it recommends assigning a version attribute to each item and using a condition expression such as attribute_not_exists(#v) OR #v < :new.

The launch blog post states that when an item is involved in an in-flight transaction, the transaction takes precedence, and the item will not be modified until the transaction is complete. No such statement was found in the developer guide (No statement found).

7.7 Where to Re-run From

Combining the content from Sections 7.1 through 7.6, the records to re-run after an operation are decided from the following three:

  • Records for objects marked as PARTIALLY_PROCESSED, NOT_PROCESSED, or NOT_AVAILABLE in the manifest, that fall outside the processedRanges.
  • Records from the ERROR report, after you correct them.
  • Records for CONDITION_CHECK_FAILURE reports, that you decide to write after reviewing the existing item.

Records that are re-run also carry condition expressions. A re-run is a new operation, and without condition expressions it overwrites both the items that the previous operation wrote and the items that the application wrote in the meantime. This article infers (Inference) that, for a FAILED operation without a manifest, the records to re-run can only be determined by comparing the table with the input data.

8. What Happens Around the Table

This chapter describes how bulk put items appear within streams, indexes, caches, metrics, and logs, and also identifies situations where they cannot be used.

8.1 DynamoDB Streams and Kinesis Data Streams

The considerations page states the following regarding tables with streams enabled:

On a table with DynamoDB Streams or a Kinesis data stream enabled, every bulk write produces a stream record, delivered at the operation's write rate. Items that fail a condition check do not produce a stream record.

The same page also notes that consumers sized for normal traffic can fall behind. It explains that because DynamoDB Streams retains records for 24 hours, consumers experiencing delays exceeding 24 hours will lose those records. It advises using MaxWriteRequestUnits to control the write rate and protect downstream consumers (see Section 9.1).

The launch blog post states that bulk write operations are reflected in the stream as if they were individual application writes. In the setup in Chapter 10, the userIdentity of the bulk write records was empty, and they could not be told apart from the records of the PutItem calls that inserted the seed items (Observation).

8.2 Secondary Indexes

Bulk put items automatically updates both global and local secondary indexes during the operation (see the considerations page). No separate steps are required to propagate data to the indexes. Writes to the indexes are metered independently.

You cannot start an operation on a table that is creating an index (see Section 8.7). On a table with a local secondary index, if an item collection exceeds the size limit, the operation will fail with a DynamoDBItemCollectionSizeLimitExceededException (see Section 7.2).

Writes to tables with vector indexes are only supported at the Standard performance tier. Requests for Accelerated performance will result in validation failures (see the considerations page).

8.3 DynamoDB Accelerator

Bulk writes do not go through DynamoDB Accelerator (DAX). The considerations page states the following:

Bulk writes bypass DAX, so items cached in DAX stay stale until their DAX TTL expires.

When using DAX, after an operation, older items may be read until the DAX Time-to-Live (TTL) expires.

8.4 CloudWatch Metrics

Bulk writes are not reflected in the ConsumedWriteCapacityUnits metric, nor do they appear in Contributor Insights. The considerations page states that this is because bulk writes do not consume capacity. It also notes that during these operations, you should track progress and failures using DescribeBulkOperation and the S3 output, rather than the table's CloudWatch metrics. The launch blog post similarly states that the table's alarms do not indicate when a bulk operation fails, and recommends distinguishing between COMPLETED and COMPLETED_WITH_ERRORS statuses.

8.5 AWS CloudTrail

The considerations page describes how AWS CloudTrail records bulk put items as follows:

  • Calls to StartBulkPutItems are logged as a management event named StartBulkOperation. The resource type is AWS::DynamoDB::BulkOperation.
  • During the operation, DynamoDB periodically emits data events for the target table, related to BulkPutItems. The resource is AWS::DynamoDB::Table, and the operation is identified by serviceEventDetails.BulkOperationArn.
  • By default, data events are not logged. To log them, you must configure your trail or event data store to record data events for DynamoDB tables.
  • A single operation may emit multiple data events related to BulkPutItems. Individual item writes are not logged as PutItem events.

While the API name is StartBulkPutItems, the event name in CloudTrail and the action name in IAM are StartBulkOperation. When you search CloudTrail for the start record, search for the name StartBulkOperation.

8.6 AWS KMS and S3 Accounts

Regarding AWS KMS, the considerations page states the following:

  • The S3SseKmsKeyId setting is required when S3SseAlgorithm is set to KMS and is not permitted when set to AES256. When providing a key ID, the S3SseAlgorithm setting is mandatory.
  • For tables encrypted with customer-managed keys, the caller must have the kms:Decrypt permission for that key. Otherwise, StartBulkPutItems will return an AccessDeniedException, and the operation will not begin.

Regarding S3 accounts, the considerations page states the following:

  • The caller must be in the table's account. Starting, retrieving status, or canceling operations from a different account will be rejected.
  • When using a bucket in a different account, specify the S3BucketOwner. DynamoDB will send the x-amz-expected-bucket-owner header, with the default value being the caller's account.
  • Using input or output buckets in a different Region may result in delayed or failed operations, potentially leading to timeouts, if that Region experiences issues. The considerations page recommends using buckets in the table's Region.

8.7 When Bulk Put Items Cannot Be Used

The sources state that the following scenarios are not supported. The replica row is the reverse case: adding a replica is rejected while an operation is running. In the other rows, an operation cannot be started.

ScenarioRelevant DocumentationStatus
Tables belonging to a global tableImportant note on the considerations pageStated as not supported
Adding a replica to a table with an active operationConsiderations pageStated as not supported
Tables undergoing index creationRunning page, considerations page. Returns a ResourceInUseException.Stated as not supported
Tables in the process of migrating to or from a global table, or tables being restored from backupConsiderations pageStated as not supported
Tables where another operation is already in progressRunning page. Returns a ResourceInUseException. Start requests that arrive at the same time can each return an ARN (Section 9.3).Stated as not supported
Accelerated operations on tables with vector indexesConsiderations pageStated as not supported

Regarding global tables, the considerations page states:

Bulk put items does not support global tables.

The launch blog post states the same matter as not supported at launch.

Importing into global tables isn't supported at launch

The developer guide explicitly states that the functionality is not supported. The launch blog post adds the qualifier that this is at launch. This article states that bulk put items does not support global tables as of November 11, 2026, and does not state that it never will. For writing to a global table, the considerations page recommends using BatchWriteItem or PutItem.

On whether a table that has left a global table can be a target of bulk put items, the materials in Section 1.3 only state that a table that is part of a global table is excluded. That a table that has left the global table can be a target if it meets the other conditions is this article's inference (Inference). The process of leaving a global table is covered on this site at Leaving an Amazon DynamoDB Global Table.

Regarding the table state, the running page states that the table must be ACTIVE, or UPDATING with a change that does not conflict with bulk writes. A statement listing which UPDATING changes do not conflict was not found in the materials in Section 1.3 (No statement found).

9. MaxWriteRequestUnits and Quotas

This chapter outlines the maximum write rate of an operation and the values of the quotas.

9.1 MaxWriteRequestUnits

MaxWriteRequestUnits defines the maximum number of write request units per second that an operation can use (running page). This limit applies to the total number of write request units used by the operation across the table and all of its indexes. For example, in a table where two global secondary indexes both project items, the running page gives the example that a limit of 1,024 allows about 340 items of 1 KB per second.

The running page indicates that this setting has no relation to the table's capacity and has a minimum value of 1,024.

This setting applies only to the bulk operation and has no relation to the table's provisioned or on-demand capacity. The minimum value is 1,024.

The API reference notes that the actual write speed may be lower than this value. MaxWriteRequestUnits represents an upper limit and does not guarantee a specific speed.

The best practices page recommends avoiding setting this value lower than necessary. A low limit can slow down operations, so that a large operation might not finish within the maximum processing time and end FAILED with Timeout, leaving the remaining items unwritten. It advises selecting the highest speed that downstream consumers can handle.

The quotas page states that the minimum value for MaxWriteRequestUnits is checked at the time of the StartBulkPutItems call. In the setup in Chapter 10, a start request with a value of 1,000 was rejected with a ValidationException, and no operation was created (Observation).

9.2 Different Things with the Same Name

On-demand tables also have a parameter named MaxWriteRequestUnits. It is passed in the OnDemandThroughput of UpdateTable and sets the maximum number of write units for the table in on-demand capacity mode. The example commands in Chapter 2 of the Amazon DynamoDB Capacity and Global Tables Guide refer to MaxWriteRequestUnits in this context.

In bulk put items, MaxWriteRequestUnits is a parameter passed to StartBulkPutItems, and it is a limit for one operation only. It does not change the table's capacity settings and is not bound by them. Although they share the same name, these two parameters apply to different things.

9.3 Quotas

The quotas page lists the following values (as of November 11, 2026).

QuotaValue
Number of concurrent operations, Standard5 per account
Number of concurrent operations, Accelerated5 per account
Number of concurrent operations per table1
Total input per operation, Standard100 GB
Total input per operation, Accelerated1 TB
Number of objects per operation50,000
Size of each input object5 GB
Minimum MaxWriteRequestUnits1,024

The quotas page specifies that the number of concurrent operations for Standard and Accelerated are counted separately, per account and Region.

The same page divides the points at which quotas are checked into two categories. The number of concurrent operations and the minimum MaxWriteRequestUnits are checked during the StartBulkPutItems call. Requests exceeding the account's concurrent operation limit will return a LimitExceededException and no operation will be created. Other quotas are checked after a successful start call, and operations exceeding these quotas will end with a status of FAILED. Exceeding the total input limit will result in a SizeLimitExceeded error, exceeding the number of objects will result in an S3ObjectsCountLimitExceeded error, and objects larger than 5 GB will result in an InputObjectTooLarge error.

Regarding start requests for the same table, the quotas page states that attempting to start an operation on a table that already has an operation in progress will return a ResourceInUseException. If multiple start requests arrive simultaneously for the same table, each may return an ARN, but all except one will end with a FailureCode of ResourceInUseException and a status of FAILED.

The table on the quotas page does not include a column indicating whether quotas can be increased (Documentation does not list). The FailureCode table on the running page lists requesting a quota increase as a possible action to address S3ObjectsCountLimitExceeded.

9.4 Performance Tiers

The PerformanceTier value can be either STANDARD or ACCELERATED, with STANDARD being the default (running page, API reference). The performance tiers page states that Standard is the default choice, suitable for most operations, while Accelerated is intended for workloads with strict completion time requirements, aiming for higher throughput. Standard is available in all commercial AWS Regions and the AWS GovCloud (US) Regions. The performance tiers page provides a list of Regions where Accelerated is available. This article does not list specific Regions.

The performance tiers page also notes that factors such as table size, item size, key distribution, the number of indexes being updated, and the available system capacity affect actual throughput. The best practices page advises that objects sorted by partition key create a rolling hot partition, where consecutive writes go to the same partition. It recommends randomizing the order before performing operations. This article does not compare the speeds of the different performance tiers.

10. Observations on a Small Table

This chapter summarizes the results of tests conducted on a small table in the us-east-1 Region on November 11, 2026 (Japan Standard Time). Each is an observation from one try on one setup (Observation), not a commitment of the documentation. This article does not use the speed values for performance comparisons.

10.1 Setup

The setup is as follows:

  • One DynamoDB table. The partition key is a string id, and it has one global secondary index with the attribute category. DynamoDB Streams is enabled with both new and old images.
  • Two S3 buckets, one for input and one for output.
  • All operations use the Standard performance tier. Input data is uncompressed DynamoDB JSON.
  • A single principal with administrator privileges invokes the operations, using the AWS SDK for Python. Minimal IAM policies have not been tested.

Before testing, five items were inserted into the table using PutItem. Each item has an origin attribute set to seed and a version attribute. The five scenarios tested are as follows. One operation each was created in R1, R2, and R3, and two in R5, for a total of five operations.

RoundInputVerification
R19 rows: an unconditional overwrite, insert-only conditions on an existing and a new key, version conditions that are newer and older on existing keys and one on a new key, a row missing its key, a row with the wrong key type, and an unconditional new rowWhere one row goes, and the two report types
R2Re-runs the correct 7 rows from R1. Requests only ERROR reports.Verification of skipped records and ClientToken.
R3A file with a row that is cut off midway, and a correct two-row file.Unread rows and the end state
R4A start request with MaxWriteRequestUnits set to 1,000.Verification at the start of the operation.
R5Two consecutive start requests sent to the same table, using different tokens.Second operation on the same table.

10.2 R1: Where One Row Goes

The R1 operation ended COMPLETED_WITH_ERRORS. The ProcessedItemCount was 9, and the FailedItemCount was 2.

  • Five rows were written. These were the unconditional overwrite, the insert-only record for a new key, the version 4 record against version 3 in the table, the version-condition record for a new key, and the unconditional record for a new key.
  • Two rows were skipped due to conditions. These were the insert-only record for an existing key and the version 4 record against version 5 in the table. Both were reported under CONDITION_CHECK_FAILURE, including the itemIndex, errorMessages containing The conditional request failed, newImage, and oldImage.
  • Two rows resulted in errors. One row failed with Missing the key id in the item and contained a newImage. The other row failed with Type mismatch for key id expected: S actual: N and did not contain a newImage.
  • Items overwritten unconditionally were completely replaced. The category attribute, which existed in the original item, was no longer present after the overwrite.

The output consisted of one manifest file, and two report files located in the internal job directory, ending in -0: errors/ and condition-check-failures/. The manifest file had a fileProcessingStatus of FULLY_PROCESSED and a processedRanges value of [[0, 8]].

When checking the status every 15 seconds, it was IN_PROGRESS at 2 seconds with a count of 0. The next status change occurred at 81 seconds, at which point it had already reached COMPLETED_WITH_ERRORS. No intermediate count changes were observed.

10.3 R2: Without the Skip Report

R2 re-ran the correct 7 rows from R1 as a separate operation. The two rows without conditions only had the origin value modified. The report type was specified as ERROR only.

The operation for R2 completed with a status of COMPLETED. ProcessedItemCount was 7, and FailedItemCount was 0. Looking at the table, only the two rows without conditions were written, while the five rows with conditions were skipped. The output consisted of only one manifest. The manifest status was FULLY_PROCESSED, and processedRanges was [[0, 6]].

The five skipped rows appeared nowhere in this operation's records: neither in the DescribeBulkOperation counts nor in the S3 output files. This matches the two statements in Section 6.1.

In R2, the following was also attempted regarding the start request:

  • Sending the start request again with the same ClientToken and parameters resulted in the return of the same operation ARN.
  • A request with the same ClientToken but a different OutputType was rejected with an IdempotentParameterMismatchException, and no operation was created.

R2, which was started with a different token than R1, functioned as a new operation and re-wrote the two rows without conditions, as described in the launch blog post referenced in Section 7.5.

10.4 R3: A Truncated Record

R3 input consists of two objects. The first object contains five rows, but the JSON on the third line is not properly closed. The second object has two valid rows.

The R3 operation completed with errors (COMPLETED_WITH_ERRORS) rather than failing. ProcessedItemCount is 5, FailedItemCount is 1, and ProcessedInputBytes and TotalInputBytes are equal. This corresponds to the second scenario described in Section 5.3.

  • The manifest indicates that the first object is marked as PARTIALLY_PROCESSED with the range [[0, 1]], while the second object is marked as FULLY_PROCESSED with the range [[0, 1]].
  • There is one row in the ERROR report, which does not include an itemIndex and contains the message Unexpected token. Remainder of the file will not be processed.
  • The two rows preceding the truncated row of the first object, and the two rows of the second object, were written to the table. The two rows following the truncated row were not in the table. These two rows are also absent from the report.

The ProcessedItemCount of 5 aligns with the sum of the two rows preceding the truncated row, the truncated row itself, and the two rows of the second object. The two unread rows appear not to be included in the count. Because a row-by-row breakdown is not provided, this is an inference from the total count (Inference).

10.5 R4 and R5: Rejection at the Start and a Second Operation on the Same Table

In R4, a start request with MaxWriteRequestUnits set to 1,000 was sent to the service. The AWS SDK for Python normally checks for a minimum value of 1,024 before sending, but this check was disabled specifically for R4. The start request was rejected with a ValidationException. The count for ListBulkOperations did not increase, and no operations were created.

1 validation error detected: Value '1000' at 'maxWriteRequestUnits' failed to satisfy constraint: Member must have value greater than or equal to 1024

In R5, two start requests were sent to the same table, with different tokens, approximately one second apart. Both requests returned an operation ARN, and the status was IN_PROGRESS. The second operation failed approximately two seconds after the start, with a FailureCode of ResourceInUseException. Neither the manifest nor the report for the second operation were present in the output S3 bucket. The first operation completed successfully. This behavior aligns with the descriptions in Sections 9.3 (quotas) and 6.4 (output).

For the first operation in R5, the count reached 2 while the status remained IN_PROGRESS after 66 seconds, and then transitioned to COMPLETED after 82 seconds. Of the four operations that processed their input to the end, this was the only one where the counts moved before the status reached an end state.

10.6 Streams and CloudTrail

After R1 through R5, all records in the table's stream were read.

  • There were records indicating either INSERT or MODIFY for each of the 13 changes written via bulk operations. These were distributed as follows: 5 in R1, 2 in R2, 4 in R3, and 2 in R5.
  • Records skipped by a condition had no stream records. The two keys skipped in R1 had only the INSERT records from when the seed items were inserted. The 5 rows skipped in R2 had no stream records either.
  • There were also no stream records for records that resulted in errors or were not read.
  • None of the records had a userIdentity value, and it was impossible to distinguish between records from bulk operations and records from inserting the seed items with PutItem based solely on the records themselves.

In the CloudTrail event history, the following was seen:

  • There were 8 requests initiating bulk operations, named StartBulkOperation. This included one request on R2 that used the same token, one request rejected with an IdempotentParameterMismatchException, and one request rejected with a ValidationException on R4, all of which were recorded as individual events.
  • DescribeBulkOperation and ListBulkOperations were also recorded as management events.
  • No trail for data events was created, so the BulkPutItems data events were not examined.

10.7 What This Setup Does Not Show

This setup does not test the following. For each of them, this article relies only on the statements in the materials in Section 1.3.

  • The Accelerated performance tier, and speed with large inputs.
  • Global tables, buckets spanning accounts, and buckets in different Regions.
  • Tables and buckets encrypted with customer-managed keys.
  • CloudTrail data events and DAX.
  • Second writes resulting from internal failover.
  • Timeout, cancellation, and CANCELLED status.
  • The page-size boundary of ListBulkOperations. The five operations created all fit in the default page size.
  • Evaluation under a minimal IAM policy that grants ListBulkOperations on bulk-operation/*.

11. Where the Sources Disagree and What They Do Not Say

This chapter collects the differences between the sources and the matters for which no statement was found.

11.1 Differences Only in Counting or Premise

The following differences are only differences in what is counted or in the premise, and this article does not call them Sources disagree.

  • Number of Status Values: The running page and the API reference list 6 possible values for BulkOperationStatus. The launch blog post states that the operation ends in one of 4 states: COMPLETED, COMPLETED_WITH_ERRORS, FAILED, and CANCELLED. The launch blog post counts the end states, which aligns with 4 of the 6 values, excluding IN_PROGRESS and CANCELLING.
  • Number of IAM Actions: The considerations page states that a minimal policy requires 5 actions. The launch blog post lists 2 actions required for initiating the operation: dynamodb:StartBulkOperation and dynamodb:BulkPutItems. The subject of the sentence in the launch blog post refers to the entity initiating the operation. The considerations page notes that with only these 2 actions, an operation can be started, but its status cannot be retrieved and it cannot be canceled.
  • Handling of Skipped Items: The launch blog post states that items skipped due to conditions are not considered failures, are included in the processed count, and that the operation completes, with the skipped items being recorded in the report. The input formats page specifies that this recording only occurs when requesting CONDITION_CHECK_FAILURE. The CLI example in the launch blog post requests both ERROR and CONDITION_CHECK_FAILURE. This article reads the wording in the launch blog post as written on the premise of that example (Inference).
  • Number of Items per Page for ListBulkOperations: The running page states that each page returns a maximum of 25 items. The API reference states that the default value for MaxResults is 10, with a maximum of 25. The maximum of 25 is consistent, while the running page does not list the default value (Documentation does not list).

The launch blog post describes the handling of skipped items as follows:

An item skipped by its condition isn't treated as a failure. It counts toward the processed total, the operation still completes, and the skip is recorded in the report.

11.2 Where the Sources Disagree

  • Table Status: The launch blog post states that the target table must be active. The running page and considerations page indicate that it can be in the ACTIVE state, or UPDATING with a change that does not conflict with bulk writes. The scope differs (Sources disagree).
  • Global Table: The considerations page states plainly that global tables are not supported. The launch blog post states that they are not supported at launch. The strength differs (Sources disagree). As of November 11, 2026, both documents agree that it is not supported.
  • ListBulkOperations Resource: The IAM table in the considerations page specifies the scope of dynamodb:ListBulkOperations as bulk-operation/*, and the example policy also associates this action with bulk-operation/*. The service reference does not assign a resource type to ListBulkOperations. It is this article's inference (Inference) that, under the usual IAM evaluation, actions without a resource type are permitted when the policy's Resource field is set to *. Because the setup in Chapter 10 ran with administrator privileges, this discrepancy has not been verified.

11.3 Items Not Found

The following items could not be found in the materials in Section 1.3, even after searching using different search terms and categories of documentation (No statement found). None of these items indicate the absence of the subject matter or its non-occurrence.

  • Relationship to Time-to-Live (TTL) values. For example, how items with a TTL attribute are handled when written using bulk put items. This article does not state that there is no impact.
  • Whether items written by bulk put items are included in point-in-time recovery (PITR) and AWS Backup. Starting an operation on a table that is being restored from a backup is covered in Section 8.7.
  • Maximum processing time values. The Timeout section in the running page does not specify a value.
  • Length and operand-count limits specific to the condition expressions of bulk put items.
  • A list of which UPDATING changes will not conflict with bulk writes.
  • Descriptions in the developer guide regarding the relationship with in-flight transactions. The launch blog post states that transactions take precedence.
  • Descriptions in the developer guide stating that ProcessedInputBytes counts bytes after compression. The launch blog post states that it counts bytes after compression. Chapter 10 only uses uncompressed input, so this has not been verified.

12. Failure Modes

This chapter collects common misreadings from the statements in Chapters 3 through 11.

  • The misreading that a FailedItemCount of 0 means all rows have been written: Rows skipped due to conditions are not included in this count. Even with a COMPLETED status, rows may still be skipped (see Sections 5.1 and 7.1). In the setup in Chapter 10, 5 of 7 rows were skipped in an operation that ended COMPLETED (see Section 10.3).
  • The misreading that ProcessedItemCount is the number of items written: This count reflects the number of records read, including those with errors and those skipped due to conditions (see Section 6.2).
  • The misreading that using only ERROR in the OutputType field indicates that skipped rows can be identified: Without requesting CONDITION_CHECK_FAILURE, no record or count of skipped rows will be retained (see Section 6.1).
  • The misreading that a condition applied to a single row applies to the entire file: Conditions are evaluated on a record-by-record basis. Records without a condition will overwrite existing items (see Section 4.4).
  • The misreading that records without a condition only modify a portion of an existing item's attributes: Items are written entirely, and any attributes not present in the record will be lost (see Section 4.3).
  • The misreading that FAILED or CANCELLED operations revert written items: Written items remain in the table (see Section 7.3).
  • The misreading that using the same ClientToken prevents overwriting when re-submitting data: The ClientToken prevents a retry of the same start request from creating a second operation. A deliberate re-run is a new operation, and what prevents overwriting is the condition expression (see Section 7.5).
  • The misreading that within a single operation, each record is written only once: Following an internal failover, the same record may be written twice (see Section 7.6).
  • The misreading that records in the processedRanges in the manifest have been written: This range includes records that were skipped due to conditions and records that resulted in errors (see Section 6.3).
  • The misreading that receiving an ARN indicates that the operation will succeed: With a wrong S3BucketOwner, or with simultaneous starts on the same table, the operation ends FAILED after the ARN is returned (see Sections 7.2 and 9.3).
  • The misreading that stream consumers sized for normal traffic are sufficient: Bulk writes produce stream records at the operation's write rate. DynamoDB Streams consumers that fall behind by more than 24 hours may lose records (see Section 8.1).
  • The misreading that an alarm on the table's ConsumedWriteCapacityUnits can monitor bulk operations: Bulk writes are not reflected in this metric (see Section 8.4).
  • The misreading that the on-demand table's MaxWriteRequestUnits and the bulk put items' MaxWriteRequestUnits are the same: These apply to different targets (see Section 9.2).
  • The misreading that CloudTrail records the start of an operation using the name StartBulkPutItems: The event name is actually StartBulkOperation (see Section 8.5).
  • The misreading that bulk put items can write to tables that belong to a global table: This functionality is not supported as of November 11, 2026 (see Section 8.7).

13. Frequently Asked Questions About DynamoDB Bulk Put Items

This chapter answers the reader assumptions in Section 1.1 using the statements in Chapters 3 through 11.

Q1. If the number of failures is 0, does that mean all input rows have been written?

Not necessarily. FailedItemCount represents the number of items that failed for deterministic reasons, and does not include items that were skipped due to conditions (see Section 5.1). COMPLETED indicates that the number of failures is 0, and the running page states in the same sentence that skipped items are possible (see Section 7.1). Skipped rows can only be identified when a CONDITION_CHECK_FAILURE report is requested (see Section 6.1).

Q2. Does ProcessedItemCount represent the number of items written?

No, it does not. The running page describes ProcessedItemCount as the number of records read, including records that failed validation or a condition check (see Section 6.2). The API reference for DescribeBulkOperation does not list a field that returns the number of items written (Documentation does not list).

Q3. If an operation ends FAILED, are the items it wrote rolled back?

No. The running page states for cancellation and timeouts, and the considerations page states for lost permissions, that items already written stay in the table (see Sections 7.3 and 7.4). How far the operation wrote is checked with the manifest and the reports. For a FAILED operation without a manifest, the table is compared with the input (see Section 7.2).

Q4. If the same file is re-run, is it written twice?

It depends on the conditions. Records without a condition overwrite the item with the same key every time the file is re-run. What the ClientToken prevents is a retry of the same start request creating two operations; a deliberate re-run is a new operation (see Section 7.5). If every row carries an insert-only condition or a version condition, a re-run does not change the existing items. In the setup in Chapter 10, re-running the correct 7 rows of R1 resulted in the 5 rows with conditions being skipped and the 2 rows without conditions being rewritten (see Section 10.3, Observation).

Q5. If attribute_not_exists is written on one row, is the whole file insert-only?

No. The condition expression is evaluated for each record, and the input formats page states that to ensure the entire file only inserts data, you need to write a condition expression for every record (Section 4.4).

Q6. Can bulk put items be used on a table in a global table?

As of November 11, 2026, it cannot be used. The considerations page states that bulk put items does not support global tables, and the launch blog post states that it is not supported at launch (Section 8.7). The considerations page also specifies that when writing to a global table, you should use BatchWriteItem or PutItem.

Q7. Can operations be monitored using the table's alarms or CloudWatch metrics?

The ConsumedWriteCapacityUnits metric and Contributor Insights do not reflect bulk write operations (see Section 8.4). The considerations page recommends tracking progress and failures using DescribeBulkOperation and S3 output.

Q8. Does setting the MaxWriteRequestUnits affect the table's capacity settings?

No, it does not. The running page states that this setting applies only to the operation and is not related to the table's provisioned or on-demand capacity (see Section 9.1). While there is a parameter with the same name for on-demand tables, it is a separate parameter (see Section 9.2).

Q9. What happens when you write items with a TTL attribute?

This article found no description in the reviewed materials regarding the relationship between bulk put items and TTL (No statement found, Section 11.3). This does not indicate that there is no impact.

14. Summary

Before using DynamoDB's bulk put items to write to an existing table, ensure the following:

  • The target table is not part of a global table and is not currently undergoing index creation (see Section 8.7).
  • All records that should not overwrite existing items have either an insert-only condition or a version condition applied (see Sections 4.4 and 7.6).
  • For input using condition expressions, the OutputType includes CONDITION_CHECK_FAILURE (see Section 6.1).
  • A procedure is defined to compare the results, not only with the FailedItemCount, but also against the manifest and two types of reports. The principal accessing the output bucket has the necessary permissions to read from it (see Sections 6.5 and 6.6).
  • The way to decide which records to re-run is defined, taking into account that some items may remain in the table if the operation ends with a FAILED or CANCELLED status (see Sections 7.3 and 7.7).
  • Wherever the start request might be retried, a ClientToken is passed (see Section 7.5).
  • The stream consumers and DAX have been checked against the operation's writes, and, if needed, MaxWriteRequestUnits is set to the highest value that the consumers can sustain (see Sections 8.1, 8.3, and 9.1).
  • You know that the start of an operation is found in CloudTrail under the name StartBulkOperation, and that item writes are not recorded unless data events are configured (see Section 8.5).
  • The developer guide has been reopened to confirm that the FailureCode table, the quotas, and the handling of global tables have not changed since the verification date of November 11, 2026 (see Section 2.2).

15. References



References:
Tech Blog with curated related content

Written by Hidekazu Konishi