With #11146 (#11139) and #11130 applied to origin/main 36892b7, the mongodb 7.5.0 fixture now connects. Its first insertMany fails because every new ObjectId() that bson generates in one process is the same value:
MongoBulkWriteError [Error]: E11000 duplicate key error collection: fx11139.documents index: _id_ dup key: { _id: ObjectId('6ab440560000000000000001') }
Repro (bson from the mongodb 7.5.0 install)
package.json is the one from #11139, with mongodb 7.5.0 and the same compilePackages list. oid.ts:
const { ObjectId } = require("bson");
const a = new ObjectId(), b = new ObjectId(), c = new ObjectId();
const hex = [a, b, c].map((o: any) => o.toHexString());
console.log("distinct", new Set(hex).size, "rand-zero", hex[0].slice(8, 18) === "0000000000", "counter-step", parseInt(hex[1].slice(18), 16) - parseInt(hex[0].slice(18), 16));
Node 26.5.1: distinct 3 rand-zero false counter-step 1
Perry (main 36892b7 + #11146 + #11130, perry-dev, Linux x64, auto-optimize on): distinct 1 rand-zero true counter-step 0
What the generated id says
For 6ab44056 0000000000 000001, the timestamp is correct, all 5 PROCESS_UNIQUE bytes are 0, and the counter is 1 on every call.
The relevant bson code is lib/bson.cjs, class ObjectId extends BSONValue, around lines 2607–2710:
static index = 0;
static PROCESS_UNIQUE = null;
static resetState = () => { this.index = Math.floor(Math.random() * 0x1000000); this.PROCESS_UNIQUE = null; };, called from a static { this.resetState(); … } block.
- The constructor does
const inc = ObjectId.getInc();, where getInc is return (ObjectId.index = (ObjectId.index + 1) % 0x1000000). It then does const pu = (ObjectId.PROCESS_UNIQUE ??= ByteUtils.randomBytes(5)); and packs the result into this.i0..i3.
A counter that stays at 1 means ObjectId.index reads as 0 on every call. So either the static write in getInc does not persist, or the read and the write resolve to different storage. It is not yet known whether the zero PROCESS_UNIQUE comes from the same fault or from crypto.getRandomValues(Buffer) (nodejsSecureRandomBytes).
I wrote a package-free imitation of those statics: static fields, an arrow resetState using this, a static block, getInc, and ??= in a static method, in both .ts and .cts. It gives Node's output on the same build, so the package's surrounding context seems to be needed. It is not minimized yet.
With #11146 (#11139) and #11130 applied to
origin/main36892b7, the mongodb 7.5.0 fixture now connects. Its firstinsertManyfails because everynew ObjectId()that bson generates in one process is the same value:Repro (bson from the mongodb 7.5.0 install)
package.jsonis the one from #11139, withmongodb7.5.0 and the samecompilePackageslist.oid.ts:Node 26.5.1:
distinct 3 rand-zero false counter-step 1Perry (main 36892b7 + #11146 + #11130, perry-dev, Linux x64, auto-optimize on):
distinct 1 rand-zero true counter-step 0What the generated id says
For
6ab44056 0000000000 000001, the timestamp is correct, all 5PROCESS_UNIQUEbytes are 0, and the counter is1on every call.The relevant bson code is
lib/bson.cjs,class ObjectId extends BSONValue, around lines 2607–2710:static index = 0;static PROCESS_UNIQUE = null;static resetState = () => { this.index = Math.floor(Math.random() * 0x1000000); this.PROCESS_UNIQUE = null; };, called from astatic { this.resetState(); … }block.const inc = ObjectId.getInc();, wheregetIncisreturn (ObjectId.index = (ObjectId.index + 1) % 0x1000000). It then doesconst pu = (ObjectId.PROCESS_UNIQUE ??= ByteUtils.randomBytes(5));and packs the result intothis.i0..i3.A counter that stays at 1 means
ObjectId.indexreads as 0 on every call. So either the static write ingetIncdoes not persist, or the read and the write resolve to different storage. It is not yet known whether the zeroPROCESS_UNIQUEcomes from the same fault or fromcrypto.getRandomValues(Buffer)(nodejsSecureRandomBytes).I wrote a package-free imitation of those statics: static fields, an arrow
resetStateusingthis, a static block,getInc, and??=in a static method, in both.tsand.cts. It gives Node's output on the same build, so the package's surrounding context seems to be needed. It is not minimized yet.