{"record":{"id":"4ae45cca950d7abb","repo":"Automattic/mongoose","slug":"can-t-validate-the-same-doc-multiple-times-in-pa","errorCode":null,"errorMessage":"Can't validate() the same doc multiple times in parallel. Document: ${doc._doc._id}","messagePattern":"Can't validate\\(\\) the same doc multiple times in parallel\\. Document: (.+?)","errorType":"exception","errorClass":"ParallelValidateError","httpStatus":null,"severity":"error","filePath":"lib/document.js","lineNumber":2760,"sourceCode":"  }\n  this.$op = 'validate';\n\n  if (arguments.length === 1) {\n    if (typeof arguments[0] === 'object' && !Array.isArray(arguments[0])) {\n      options = arguments[0];\n      pathsToValidate = null;\n    }\n  }\n  if (options && typeof options.pathsToSkip === 'string') {\n    const isOnePathOnly = options.pathsToSkip.indexOf(' ') === -1;\n    options.pathsToSkip = isOnePathOnly ? [options.pathsToSkip] : options.pathsToSkip.split(' ');\n  }\n  const _skipParallelValidateCheck = options?._skipParallelValidateCheck;\n\n  if (this.$isSubdocument != null) {\n    // Skip parallel validate check for subdocuments\n  } else if (this.$__.validating && !_skipParallelValidateCheck) {\n    throw new ParallelValidateError(this);\n  } else if (!_skipParallelValidateCheck) {\n    this.$__.validating = true;\n  }\n\n  const hasValidateHooks = this.$__middleware.hasHooks('validate');\n  try {\n    try {\n      if (hasValidateHooks) {\n        [options] = await this._execDocumentPreHooks('validate', options, [options]);\n      } else if (!_skipParallelValidateCheck) {\n        // Even with no validate hooks, preserve the async boundary that the pre\n        // hook `await` used to provide so that the parallel validate check still\n        // observes `$__.validating` across a tick (gh-8468). insertMany's per-doc\n        // validate passes `_skipParallelValidateCheck` and stays fully synchronous.\n        await Promise.resolve();\n      }\n    } catch (error) {\n      if (hasValidateHooks) {","sourceCodeStart":2742,"sourceCodeEnd":2778,"githubUrl":"https://github.com/Automattic/mongoose/blob/49cdab01366679723b487ecb754b38570f783289/lib/document.js#L2742-L2778","documentation":"ParallelValidateError: validate() sets an internal `$__.validating` flag for the duration of async validation; a second validate() on the same document before the first finishes throws this error (message includes the document's _id). Subdocuments skip the check entirely.","triggerScenarios":"`Promise.all([doc.validate(), doc.validate()])`; calling doc.validate() while doc.save() (which itself validates) is still in flight; two concurrent request handlers validating the same document instance.","commonSituations":"Document instances shared across parallel requests; hooks that validate while the caller also validates; retry loops that overlap an in-flight validation; fire-and-forget validate calls.","solutions":["Serialize validations: await the first validate() before starting another, or cache the in-flight promise and reuse it","Let save() drive validation instead of validating and saving in parallel","Catch ParallelValidateError and retry after the running validation settles","As a last resort pass `{ _skipParallelValidateCheck: true }` (internal option, use with care)"],"exampleFix":"// before\nawait Promise.all([doc.validate(), doc.validate()]); // second call throws ParallelValidateError\n\n// after (share one in-flight validation)\ndoc.__validate = doc.__validate ?? doc.validate();\nawait doc.__validate;","handlingStrategy":"retry","validationCode":"// Serialize validations on a shared document instance\ndoc.__validate = doc.__validate ?? doc.validate().finally(() => { delete doc.__validate; });\nawait doc.__validate;","typeGuard":null,"tryCatchPattern":"try {\n  await doc.validate();\n} catch (err) {\n  if (err instanceof mongoose.Error.ParallelValidateError) {\n    await new Promise(resolve => setImmediate(resolve)); // let the in-flight validation finish\n    return doc.validate();\n  }\n  throw err;\n}","preventionTips":["Never call validate() twice concurrently on the same document instance","Share one in-flight validation promise across handlers that need the same doc","Remember save() validates too - do not race validate() against save()"],"tags":["mongoose","validate","concurrency","parallel"],"backgroundTag":"parallel-validation","analyzedSha":"49cdab01366679723b487ecb754b38570f783289","analyzedAt":"2026-08-21T22:54:00.882Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}