Tags firestore indexfirebasefailed-preconditiondeploymentcomposite index
All posts

firestore index

The Firestore index deployed and the error stayed

I deployed a Firestore index, relaunched, and got the identical failed-precondition error. The deploy was fine. A building index reports exactly like a missing one.

August 15, 2026 4 min

A red toast sat at the bottom of the app. A listener reading blood sugar records kept failing.

The full error said a composite index was required. I added the definition to firestore.indexes.json, deployed it, force-quit the app, relaunched, and opened that screen.

The error was still there, word for word.

The deploy reported success

Deploying the Firestore index printed exactly what you would want to see:

i  firestore: deploying indexes...
✔  firestore: deployed indexes in firestore.indexes.json successfully
✔  Deploy complete!

I checked the definition too:

npx firebase-tools firestore:indexes --project <project>

Mine was in the list. Right fields, right order, right collection.

At that point I stopped suspecting indexing at all. I looked at security rules, re-read the query field names, and checked whether the app was serving a stale bundle. None of it was the problem.

I want to be precise about how wrong this was, because the wrongness is the useful part. Every piece of evidence available to me said the work was done. The command said success. The definition listing said it existed. The only thing that disagreed was the app, and the app is the thing I trusted least because apps cache.

A listed Firestore index may still be unusable

firestore:indexes prints definitions. It does not tell you whether a definition can currently serve a query.

For that you have to read the state from the Admin REST API:

GET https://firestore.googleapis.com/v1/projects/<pid>/databases/(default)/collectionGroups/<collection>/indexes

Each entry carries a state. Mine said CREATING.

I waited and read it again. It flipped to READY. I relaunched the app, the toast was gone, and grepping the log for that error over the same window returned zero hits.

The deploy had been correct the whole time. I had just looked at the result before the build finished.

Building and missing produce the same message

While it builds, the query returns the same error it returns when nothing exists at all:

[firestore/failed-precondition] The query requires an index.
You can create it here: https://console.firebase.google.com/...

It does not say “building”. It says “create it here”, and it hands you a console link. If you just created it, that link reads as proof that your creation did not land. That is exactly how I read it.

This is the part worth keeping: the error is indistinguishable, so the screen cannot tell you which of the two states you are in. Only the API can. Any debugging you do from the client side during that window is debugging with a broken instrument.

Eight minutes on an empty collection

The collection had effectively no documents in my project. The build still took roughly eight minutes to go from CREATING to READY.

That number is one measurement from one project on one day. It is not a documented guarantee, and a large collection will take longer. What it does disprove is the assumption I was working from, which was that an empty collection indexes instantly.

I do not know what build time actually scales with. I cannot explain why a near-empty collection took eight minutes, and I did not find a documented answer.

I changed the order I check things in

I used to deploy and then look at the app. Now I deploy, poll state until it reads READY, and only then look at the app. That way any error still on screen is definitely not an indexing story.

The poll is short enough to inline with a service account:

const url = `https://firestore.googleapis.com/v1/projects/${pid}` +
  `/databases/(default)/collectionGroups/${col}/indexes`;
const r = await fetch(url, {headers: {Authorization: `Bearer ${token}`}});
const j = await r.json();
console.log(j.indexes.map(i => i.state).join(','));

Do not delete what your file does not know about

One related thing worth knowing. If your project has definitions that are not in your file, the deploy says:

i  firestore: there are 16 indexes defined in your project that are not
   present in your firestore indexes file. To delete them, run this
   command with the --force flag.

I did not pass --force. I did not know what those 16 were serving.

Deleting a live one starts producing the very error I had just spent an hour on, and rebuilding it means waiting out that eight minutes again. The delete is one flag. The recovery is not.

The link in the error opens a prefilled creation form. Clicking it is faster, and it was tempting during the hour I thought nothing had landed.

I avoided it for one reason. An index created that way exists in the project but not in firestore.indexes.json, so it becomes one of those unlisted entries that the next deploy offers to delete. You end up with a definition that only survives as long as nobody runs the deploy command with --force.

That is the same drift that produced the 16 unlisted entries I found above. I do not know which of those started life as a console click, but the shape fits.

Reading the error the UI truncates

The toast cuts the message off. I read the full text from the simulator log:

xcrun simctl spawn <device> log show --last 5m --style compact \
  | grep -i "bloodSugar"

Note that console.error reaches the iOS native log and console.warn does not. That is a good reason to log listener failures at error level from the start, because a failing listener otherwise looks exactly like an empty result set.

Scope

Verified on 2026-08-15 with firebase-tools 15.19.0 against one Firestore project in native mode. Two-field composite definition on a single collection, roughly eight minutes to build.

I did not look at what other values state can take beyond CREATING and READY, and I do not know what a failed build reports. I will measure that if it ever happens to me.

Previous Turning off the auto popup removed the only entry point