{"record":{"id":"4af13f1b1de1d422","repo":"mongodb/node-mongodb-native","slug":"unreachable-state-machine-state-entered-mongocryp","errorCode":null,"errorMessage":"unreachable state machine state: entered MONGOCRYPT_CTX_NEED_MONGO_COLLINFO but metadata client is undefined","messagePattern":"unreachable state machine state: entered MONGOCRYPT_CTX_NEED_MONGO_COLLINFO but metadata client is undefined","errorType":"exception","errorClass":"MongoCryptError","httpStatus":null,"severity":"critical","filePath":"src/client-side-encryption/state_machine.ts","lineNumber":195,"sourceCode":"    let result: Uint8Array | null = null;\n\n    // Typescript treats getters just like properties: Once you've tested it for equality\n    // it cannot change. Which is exactly the opposite of what we use state and status for.\n    // Every call to at least `addMongoOperationResponse` and `finalize` can change the state.\n    // These wrappers let us write code more naturally and not add compiler exceptions\n    // to conditions checks inside the state machine.\n    const getStatus = () => context.status;\n    const getState = () => context.state;\n\n    while (getState() !== MONGOCRYPT_CTX_DONE && getState() !== MONGOCRYPT_CTX_ERROR) {\n      options.signal?.throwIfAborted();\n      debug(`[context#${context.id}] ${stateToString.get(getState()) || getState()}`);\n\n      switch (getState()) {\n        case MONGOCRYPT_CTX_NEED_MONGO_COLLINFO: {\n          const filter = deserialize(context.nextMongoOperation());\n          if (!metaDataClient) {\n            throw new MongoCryptError(\n              'unreachable state machine state: entered MONGOCRYPT_CTX_NEED_MONGO_COLLINFO but metadata client is undefined'\n            );\n          }\n\n          const collInfoCursor = this.fetchCollectionInfo(\n            metaDataClient,\n            context.ns,\n            filter,\n            options\n          );\n\n          for await (const collInfo of collInfoCursor) {\n            context.addMongoOperationResponse(serialize(collInfo));\n            if (getState() === MONGOCRYPT_CTX_ERROR) break;\n          }\n\n          if (getState() === MONGOCRYPT_CTX_ERROR) break;\n","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/dce7939f86fb283e167ad709955abedb7bf23124/src/client-side-encryption/state_machine.ts#L177-L213","documentation":"An internal 'this should never happen' guard in the CSFLE state machine. MONGOCRYPT_CTX_NEED_MONGO_COLLINFO means libmongocrypt wants collection metadata (JSONSchema, validation) to decide what to encrypt, but the executor has no metaDataClient. The metadata client is the application's MongoClient used for auto-discovery; it is only absent in certain explicit-encryption-only configurations.","triggerScenarios":"Auto-encryption that needs collection info but was constructed without a metaDataClient / keyVaultClient wired correctly; using a ClientEncryption (explicit) context where an auto-encryption context was expected; a driver bug or an incompatibility between driver and libmongocrypt versions causing an unexpected state transition.","commonSituations":"Version skew between mongodb driver, mongodb-client-encryption, and libmongocrypt; misconfigured AutoEncryption extraOptions; passing a closed/dereferenced MongoClient as the metaData client; custom StateMachine usage in tests.","solutions":["Ensure the MongoClient used for autoEncryption is open and healthy and that keyVaultNamespace is set — the driver derives the metadata client from it.","Align versions: use compatible mongodb, mongodb-client-encryption, and libmongocrypt releases per the driver's CSFLE compatibility matrix.","If using explicit ClientEncryption only (no auto-encryption), make sure you are not triggering a code path that expects collection metadata (e.g. set schemaMap to avoid the collinfo lookup).","Report a bug with driver, mongodb-client-encryption, and libmongocrypt versions if the configuration is correct."],"exampleFix":"// before: autoEncryption needs collinfo but no usable metadata client\nnew MongoClient(uri, {\n  autoEncryption: {\n    keyVaultNamespace: 'encryption.__keyVault',\n    kmsProviders,\n    // schemaMap missing and collection has no JSONSchema -> needs collinfo\n  }\n});\n// after: provide a schemaMap so collinfo lookup is unnecessary\nnew MongoClient(uri, {\n  autoEncryption: {\n    keyVaultNamespace: 'encryption.__keyVault',\n    kmsProviders,\n    schemaMap: { 'db.coll': { bsonType: 'object', properties: { ssn: { encrypt: { ... } } } } }\n  }\n});","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep mongodb, mongodb-client-encryption, and libmongocrypt/crypt_shared versions aligned per the CSFLE compatibility matrix.","Provide a schemaMap for auto-encryption so the collinfo state is avoided.","Ensure the keyVaultNamespace MongoClient is open before issuing encrypted operations."],"tags":["csfle","client-side-encryption","internal","version-skew"],"backgroundTag":null,"analyzedSha":"dce7939f86fb283e167ad709955abedb7bf23124","analyzedAt":"2026-08-11T04:54:53.215Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}