{"record":{"id":"d645e270733d0391","repo":"mastra-ai/mastra","slug":"knowledge-record-version-conflict-id","errorCode":null,"errorMessage":"Knowledge record version conflict: ${id}","messagePattern":"Knowledge record version conflict: (.+?)","errorType":"exception","errorClass":"KnowledgeConflictError","httpStatus":null,"severity":"error","filePath":"packages/core/src/storage/domains/knowledge/inmemory.ts","lineNumber":207,"sourceCode":"        node =>\n          !cursor ||\n          node.updatedAt < cursor.updatedAt ||\n          (node.updatedAt.getTime() === cursor.updatedAt.getTime() &&\n            (node.name > cursor.name || (node.name === cursor.name && node.id > cursor.id))),\n      )\n      .slice(0, input.limit ?? 100)\n      .map(cloneNode);\n  }\n\n  async updateNode(input: UpdateKnowledgeNodeInput): Promise<KnowledgeNode> {\n    return this.#runAtomicMutation(() => this.#updateNode(input));\n  }\n\n  #updateNode(input: UpdateKnowledgeNodeInput): KnowledgeNode {\n    assertKnowledgeDescriptionWithinBound(input.description);\n    const existing = this.#db.knowledgeNodes.get(input.id);\n    if (!existing) throw new KnowledgeNotFoundError('node', input.id);\n    if (existing.version !== input.version) throw new KnowledgeConflictError(input.id);\n    if (existing.mergedInto) throw new Error(`Cannot update merged knowledge node: ${input.id}`);\n\n    const scope = canonicalizeKnowledgeScope(input.scope ?? existing.scope);\n    const name = (input.name ?? existing.name).trim();\n    const oldKey = recordKey(existing.name, existing.scope);\n    const newKey = recordKey(name, scope);\n    const collision = this.#db.knowledgeNodeKeys.get(newKey);\n    if (collision && collision !== input.id) throw new Error(`Knowledge node already exists in scope: ${name}`);\n\n    const updated: KnowledgeNode = {\n      ...existing,\n      name,\n      kind: input.kind ?? existing.kind,\n      content: input.content ?? existing.content,\n      description: input.description ?? existing.description,\n      scope,\n      version: existing.version + 1,\n      updatedAt: new Date(),","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/storage/domains/knowledge/inmemory.ts#L189-L225","documentation":"updateNode performs optimistic concurrency control: the stored node's version must equal input.version. A mismatch means the node was modified (or merged) by someone else since the caller last read it, so the update is rejected with KnowledgeConflictError to prevent lost updates.","triggerScenarios":"Calling updateNode({ id, version }) where existing.version !== input.version — e.g. two concurrent updates, an update after a mergeNodes bumped the version, or the caller cached a stale version across calls.","commonSituations":"Multiple agents/workflows editing the same knowledge node concurrently; long-running job holding a version while another request updates the node; retrying an update after a successful first attempt.","solutions":["Re-read the node (getNode) to get the current version and retry the update with it once","Implement a retry loop around updateNode that refetches the version on KnowledgeConflictError (bounded retries)","Serialize updates per node (queue/lock) if concurrent writers are common"],"exampleFix":"// before\nawait store.updateNode({ id, version: cachedVersion, description });\n// after\nlet node = await store.getNode({ id, resolutionScope: scope });\nfor (let i = 0; i < 3; i++) {\n  try { node = await store.updateNode({ id, version: node.version, description }); break; }\n  catch (e) { if (e instanceof KnowledgeConflictError) node = await store.getNode({ id, resolutionScope: scope }); else throw e; }\n}","handlingStrategy":"retry","validationCode":"const current = await store.getNode({ id, resolutionScope: scope });\nif (current.version !== cachedVersion) {\n  // refresh your local copy before attempting the update\n  cachedVersion = current.version;\n}","typeGuard":"function isFresh(node: { version: number }, expectedVersion: number): boolean {\n  return node.version === expectedVersion;\n}","tryCatchPattern":"try {\n  await store.updateNode({ id, version, ...patch });\n} catch (e) {\n  if (e instanceof KnowledgeConflictError) {\n    const fresh = await store.getNode({ id, resolutionScope: scope });\n    await store.updateNode({ id, version: fresh.version, ...patch });\n  } else throw e;\n}","preventionTips":["Always read the node immediately before updating instead of caching versions","Bound retries (e.g. 3 attempts) when refetching versions","Avoid multiple writers updating the same node concurrently; queue writes per node","Re-apply your patch onto the freshly read node rather than blindly overwriting"],"tags":["knowledge-store","optimistic-concurrency","version-conflict","retry"],"backgroundTag":"version-conflict","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}