firebase-tools
firebase-tools copied to clipboard
Firestore emulator not throwing an error for oversized batches
[REQUIRED] Environment info
firebase-tools: 13.11.0 (also present in latest major v14) Platform: macOS 15.3.2
[REQUIRED] Test case
We have a custom utility that splits a big batch into multiple smaller batches if it would be too much data for a single batch to handle. For the sake of simplicity, the minimal repro won't consider the utility and reproduce the issue itself.
We are testing Firestore emulator behavior with an oversized WriteBatch to simulate and handle the Transaction too big. Decrease transaction size error.
Minimal repro:
import { initializeApp } from 'firebase-admin/app';
import { getFirestore } from 'firebase-admin/firestore';
process.env.FIRESTORE_EMULATOR_HOST = 'localhost:5001'
const app = initializeApp({ /* init for emulator */ });
const firestore = getFirestore(app);
const batch = firestore.batch();
const collection = firestore.collection('test_batch');
const largeString = 'a'.repeat(8000); // ~8KB payload
for (let i = 0; i < 1500; i++) {
const ref = collection.doc();
batch.set(ref, {
field: 'value',
largeString, // 8kb * 1500 = 12mb~
});
}
await batch.commit(); // <-- Should throw
[REQUIRED] Steps to reproduce
- Use any
firebase-toolssince13.11.0. This behaviour is not present in previous versions. - Start the Firestore emulator (
firebase emulators:start --only firestore) - Run the script above (in a test or standalone)
- Observe result with emulator 1.19.4 vs 1.19.7
[REQUIRED] Expected behavior
The commit should throw:
Error: 3 INVALID_ARGUMENT: Transaction too big. Decrease transaction size.
This allows code to detect and respond to the error, e.g., by splitting the batch.
This is an example of a production (non emulated firestore) stack trace for this scenario:
Error: 3 INVALID_ARGUMENT: Transaction too big. Decrease transaction size.
at Object.callErrorFromStatus (/app/node_modules/@google-cloud/firestore/node_modules/@grpc/grpc-js/build/src/call.js:31:19)
at Object.onReceiveStatus (/app/node_modules/@google-cloud/firestore/node_modules/@grpc/grpc-js/build/src/client.js:190:52)
at Object.onReceiveStatus (/app/node_modules/@google-cloud/firestore/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:365:141)
at Object.onReceiveStatus (/app/node_modules/@google-cloud/firestore/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:328:181)
at /app/node_modules/@google-cloud/firestore/node_modules/@grpc/grpc-js/build/src/call-stream.js:188:78
at process.processTicksAndRejections (node:internal/process/task_queues:85:11)
for call at
at ServiceClientImpl.makeUnaryRequest (/app/node_modules/@google-cloud/firestore/node_modules/@grpc/grpc-js/build/src/client.js:160:30)
at ServiceClientImpl.<anonymous> (/app/node_modules/@google-cloud/firestore/node_modules/@grpc/grpc-js/build/src/make-client.js:105:19)
I also manually replaced the firestore emulator version inside my node_modules and confirmed that the issue is with the emulator itself, not this package or firebase-admin.
[REQUIRED] Actual behavior
Since upgrading to emulator 1.19.7:
- No error is thrown
- The script/test hangs indefinitely
- Emulator logs show no failure or response
Rolling back to emulator 1.19.4 restores the expected behavior.
This regression makes it impossible to test batch-splitting logic locally or in CI. Please advise if this is a known change in emulator behavior or a bug.
Thanks for your work on these tools!
Hey @kaisermann, thanks for the detailed report! I’m able to reproduce the issue where running the script hangs indefinitely when using firebase-tools >= 13.11.0. However, I can’t seem to reproduce the behavior of the script throwing an error like
Error: 3 INVALID_ARGUMENT: Transaction too big. Decrease transaction size.
In my case, running the script throws an error like:
Error: 1 CANCELLED: Call cancelled
Here’s the current mcve I have. I’m not sure why we’re encountering different errors here. Could you let me know which version of Node.js, Java, and firebase-admin you’re using? If you spot anything missing from the mcve, please let me know.
I’ll also raise this to our engineering team.
This certainly seems like a bug in the Firestore emulator binary. I've filed a bug with the Firestore team to take a look at this - internal tracking number is b/420660158
Thanks for the replies, @aalej and @joehan!
To clarify, the expected behavior should ideally match production, which throws a 3 INVALID_ARGUMENT error for oversized transactions. The older emulator versions threw a 1 CANCELLED instead, which was already somewhat misleading, but at least it surfaced an error. I had forgotten to mention this difference in the issue, my bad!
The current behavior (hanging with no response) unfortunately makes it even harder to debug or simulate proper handling, so it feels like a regression.
Appreciate you raising it with the team!
Thanks @kaisermann for raising this, a couple of comments:
The older emulator likely was throwing CANCELLED due to an oversized network payload and not due to the transaction size limit. The hanging we are now seeing is likely some issue at the network layer not handling the large payloads well anymore (this we are able to address).
The transaction size limit & the network request size limits here are differently, with the transaction size limit also including the size of all index writes that need to occur, not just the size of the overall RPC. Depending on the overall fanout of the number of indexes to be updated, these two can diverge drastically. Depending on the type of workloads you are trying to validate, it can make sense to just test against the production version directly.
@JDrit thanks for the reply and explanation!
After I filed this issue, I recently discovered that we were accidentally pinning the @google-cloud/firestore version to v5 instead of the latest v7 major. After fixing that, I can confirm that we are getting a CANCELLED exception.
Strangely enough, after we catch that exception and try to split the big batch into smaller ones, the calls hang indefinitely as the original repro.