---
title: "When a DynamoDB vector index is actually ready - Martin Hicks"
description: "AWS said to wait for IndexStatus ACTIVE and Backfilling false. I measured it, and that state never happens. AWS have since rewritten the docs."
canonical: https://martinhicks.dev/articles/dynamodb-vector-search-docs-get-wrong
last-updated: 2026-08-20
---

![A scattered cloud of glowing amber points on a near-black background, with one bright point at the centre joined to its three closest neighbours by thin lines](https://martinhicks.dev/images/articles/dynamodb-vector-search-docs-get-wrong.png)13th August 2026

# When a DynamoDB vector index is actually ready

**Update, 20th August 2026.** Morgan Willis at AWS replied to [my LinkedIn post about this](https://www.linkedin.com/posts/martin-hicks-8061748_when-a-dynamodb-vector-index-is-actually-activity-7493950905621504000-KOqi) to say she was passing it on internally for someone to look at. A few days later Deepthi Mohan, a principal product manager there, followed up to say the documentation had been updated. It has, and all three problems below are fixed.

The tutorial's contradiction is gone. It now says searching during backfill returns a `ValidationException` and "does not return partial results". The ACTIVE-with-`Backfilling: true` state has been taken out of every page and replaced with the sequence I measured: CREATING while it backfills, then ACTIVE with the field absent. The check they now tell you to write is `Backfilling` is not `true`, which is the one that works on both paths. And the early-ACTIVE window has its own callout, headed "A newly ready index is not immediately searchable", plus a troubleshooting row and the advice to prove readiness with a real search in a retry loop.

Two other things I hit are documented now as well: that backfill duration doesn't track the size of the table, and the one-index-at-a-time limit with its `LimitExceededException` text.

One line survived. The [troubleshooting page](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/VectorSearchTroubleshooting.html)'s walkthrough for adding a partition key to an existing index still says, at step 2, to "confirm that `IndexStatus` is `ACTIVE` and `Backfilling` is `false`". Two paragraphs further up, the same page says not `true`. I imagine that'll get tidied up in due course too, so don't be surprised if it's gone by the time you read this.

The rest of this article is as published. Every quote in it is what the pages said on 12th August, [pinned in the capture file](https://github.com/paritysuite/dynamodb-conformance/blob/80b6ef79078386759d16a2bf9c88e972f4e73fd2/captures/2026-08-12-vector-backfill-docs.json).

AWS shipped [vector search for DynamoDB](https://aws.amazon.com/blogs/aws/amazon-dynamodb-now-supports-real-time-vector-search-at-any-scale/) on 5th August, straight to GA. I spent a couple of days pinning it down against real DynamoDB so I could add it to my [conformance suite](https://paritysuite.org), which meant reading the docs properly and then checking whether they were true.

Mostly they are. But there's one thing they get wrong three different ways, and the three stack up: knowing when a vector index is ready to search.

## The tutorial contradicts everything else

Add a vector index to a table that already has data in it and there's a gap before you can use it, while DynamoDB backfills the index from the items you already have. What happens if you search during that gap depends on which page you read.

Three pages say you get an error. The [data synchronisation page](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/VectorSearchDataSync.html) puts it plainly:

> New writes to the base table are replicated to the index during this phase, but `SearchVectors` returns an error until backfilling finishes.

[Creating and searching](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/VectorSearchWorkingWith.html) has a callout headed "You can't search while the index is backfilling", and [troubleshooting](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/VectorSearchTroubleshooting.html) carries a row for it. The [tutorial](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/VectorSearchTutorial.html) says something different:

> Searching an index that is not yet `ACTIVE` fails, and searching during backfill can return incomplete results.

Those aren't the same problem at all. An error you catch and retry. Incomplete results you can't spot, because a short answer from an approximate search looks exactly like a short answer from a thin index. If the tutorial were right, every search during a backfill would be quietly wrong with nothing to tell you.

It isn't right. You get an error, and there are two of them depending on how far along the index is:

```
ValidationException: The table does not have the specified index: vix
ValidationException: Cannot search backfilling vector index: vix
```

So trust the other three. Worth saying out loud, because the tutorial is the page you'd be following if this is your first vector index.

_Since fixed. The tutorial now says a search before `ACTIVE` and a search during backfill both return a `ValidationException`, and spells out that it "does not return partial results"._

## The state machine doesn't exist

This is the one that would actually bite.

Those three pages all describe the index moving through the same three states: CREATING while DynamoDB sets up the infrastructure, then a middle state, then ACTIVE with `Backfilling: false` once it's done. The data synchronisation page names the middle one:

> It then moves to `IndexStatus` `ACTIVE` with `Backfilling` set to `true` while DynamoDB populates the index from existing base table data.

Every piece of waiting advice in the documentation hangs off that state.

I polled `DescribeTable` every five seconds through the creation of an index added to a table that already had items in it. This is what I got:

```
CREATING   Backfilling: false
CREATING   Backfilling: true
ACTIVE     Backfilling: (gone)
```

There's no middle state. `Backfilling` is a CREATING-time field, and when the index flips to ACTIVE the field doesn't settle to false, it vanishes from the response.

That breaks the advice, because the advice tells you to wait for a value that never arrives. Data synchronisation again, in the sentence straight after the one I quoted earlier:

> Use `DescribeTable` and wait until `IndexStatus` is `ACTIVE` and `Backfilling` is `false` before you search.

Write that literally and your poll never finishes. By the time the status is ACTIVE, `Backfilling` is `undefined`, not `false`. One page out of the four allows for that, and it does it in a parenthesis: "`Backfilling` set to `false` (or absent)".

If you are gating on the description, `Backfilling !== true` is the check that survives both paths. Absent means done, the same as false does.

Create the index as part of `CreateTable` instead of adding it later and the field never turns up at all. That one I do assert, on every poll, so if AWS starts reporting it my tests break:

```js
expect(ix?.Backfilling).toBeUndefined()
```

Let me be straight about the evidence, though, because the two halves aren't equally solid. That assertion is real and runs on every scheduled run. The three-line transcript above isn't pinned: it's something I recorded on 11th August, and the test only checks the field showed up at some point, without checking that `true` appears solely alongside CREATING. It's [in the capture file](https://github.com/paritysuite/dynamodb-conformance/blob/80b6ef79078386759d16a2bf9c88e972f4e73fd2/captures/2026-08-12-vector-backfill-docs.json) with the documented version quoted next to it if you want to check the mismatch yourself. A gap in my tests rather than in the finding, and it's on the list.

_Since fixed. All four pages now keep the index at CREATING through the backfill and have `Backfilling` disappear once it goes ACTIVE, and the check they document is `Backfilling` is not `true`. One walkthrough still says to wait for `false`, noted at the top._

## ACTIVE arrives too early

Even once the status says ACTIVE, the index can still not be ready.

`DescribeTable` goes ACTIVE a beat before the search plane agrees. Search on that first ACTIVE and you get failures that look like flakiness and aren't. It's a small window, which is worse than a big one: a window small enough to survive your local testing still opens wherever things run fastest.

That bites hardest when you create the index with the table, because there's no `Backfilling` field on that path and the tutorial tells you to go on status alone:

> Use `IndexStatus` alone as your signal in that case.

Status alone is the signal that arrives early.

_Since fixed. Creating and searching carries a callout for this now, headed "A newly ready index is not immediately searchable", troubleshooting has a row for it, and the tutorial adds that the search endpoint can need longer than `DescribeTable`. All three say to treat the `ValidationException` as retryable._

## How to wait for it properly

Prove the index is ready with a search, not with a description. My suite polls until a search comes back with everything it put in:

```js
while (true) {
  try {
    const res = await ddb.send(new SearchVectorsCommand({
      TableName, IndexName, SearchVector, TopK: 5,
    }))
    if ((res.SearchResults ?? []).length === expectedCount) break
  } catch (err) {
    // Not ready yet. Anything else is a real failure.
    if (err.name !== 'ValidationException') throw err
  }
  await new Promise(r => setTimeout(r, 5000))
}
```

The count check earns its place as much as the try/catch does. A search can start succeeding while the index still has a partial view of your data, so a bare "did it throw" test lets you through early with fewer results than you wrote.

Budget some time for it too. An index added to a table holding 25 items took about 17 minutes to become searchable. It's running on the same online-index machinery as a GSI, and the size of the table isn't what drives that number. It inherits the GSI concurrency limit as well, error message and all:

```
LimitExceededException: Subscriber limit exceeded: Only 1 online index
can be created or deleted simultaneously per table
```

_Both documented since. Creating and searching says to prove readiness by issuing a real `SearchVectors` request in a retry loop, and carries this limit with the same error text. Data synchronisation adds that backfill duration comes from index construction rather than the number of items in the table._

## Other things worth knowing

**The index keeps your embeddings at f32 and the table doesn't.** The docs do say this, so it's not a discovery, but it's worth seeing how big the gap is. `16777217` is the first integer a 32-bit float can't hold. Write it into an embedding and the base table gives it back exactly. Ask for the same attribute through a search projection and you get `16777216`. The index also prints its f32 copy as the shortest decimal that names the float, so `0.1` comes back as `0.1` rather than `0.100000001490116119384765625`, which makes the whole thing harder to notice than it sounds.

**Vector capacity has a shape nothing else in DynamoDB uses.** A search reports a bare object with no capacity units and no table name:

```js
{ VectorSearchRequestBytes: 1024 }
```

Writes report a `VectorIndexes` map, but only under `ReturnConsumedCapacity: 'INDEXES'`. Ask for `TOTAL` and you get nothing vector-related at all, not even rolled into the total, so the two modes aren't detail levels of the same number here.

That 1024 is interesting on its own. A three-dimension vector is twelve bytes of f32, so it looks like a 1KB floor rather than anything to do with the size of your vector. One run isn't enough to assert a formula, so my tests check it's positive and stop there.

**No emulator implements any of this yet.** I score eight DynamoDB emulators against real AWS on every run and all eight skip the whole family. DynamoDB Local is the one to watch: it takes `VectorIndexes` on `CreateTable` quite happily and then silently drops them, so a `DescribeTable` afterwards shows no indexes at all. If you're testing locally against it, the vector index you think you created isn't there.

**You need a recent SDK.** `@aws-sdk/client-dynamodb` 3.1103.0 or later.

## The evidence

Both sides of the backfill contradiction are in [captures/2026-08-12-vector-backfill-docs.json](https://github.com/paritysuite/dynamodb-conformance/blob/80b6ef79078386759d16a2bf9c88e972f4e73fd2/captures/2026-08-12-vector-backfill-docs.json), dated, with their URLs and anchors, along with the documented state machine, the transcript that doesn't match it, and which of the two paths is pinned by an assertion. Check any of it rather than taking my word for it.

The tests live in the same repo under `tests/tier2/vectorSearch` and run against real DynamoDB on a schedule, so if AWS changes something here I'll find out. If you've hit anything else in it, [tell me](https://github.com/paritysuite/dynamodb-conformance/issues) and I'll add a test.

## Further reading

-    [Parity Suite 3.0.0: measuring the wrong thing
    
    Parity Suite 3.0.0 splits the old conformance percentage into divergence and coverage, grades every DynamoDB emulator from A to F, and takes the suite to 1,054 tests with the first coverage of DynamoDB's new vector search.](https://martinhicks.dev/articles/parity-suite-300-release-notes)
-    [What a write to an indexed DynamoDB table costs
    
    What a write to a DynamoDB table carrying GSIs and LSIs actually costs, measured against real DynamoDB in eu-west-2 rather than lifted from the docs.](https://martinhicks.dev/articles/what-a-write-to-an-indexed-dynamodb-table-costs)
-    [What a conditional DynamoDB transaction actually costs
    
    The AWS docs aren't clear on what a conditional TransactWriteItems costs in capacity units, so I ran it against real DynamoDB and pinned the numbers.](https://martinhicks.dev/articles/what-a-conditional-dynamodb-transaction-costs)
-    [How close is your DynamoDB emulator to AWS?
    
    The DynamoDB conformance suite now has a home: eight emulators and 684 tests scored against live AWS DynamoDB, with results published on every run.](https://martinhicks.dev/articles/dynamodb-conformance-org)

---

Source: https://martinhicks.dev/articles/dynamodb-vector-search-docs-get-wrong
