{"record":{"id":"4118554cdefbce92","repo":"mastra-ai/mastra","slug":"cannot-update-merged-knowledge-node-input-id","errorCode":null,"errorMessage":"Cannot update merged knowledge node: ${input.id}","messagePattern":"Cannot update merged knowledge node: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/storage/domains/knowledge/inmemory.ts","lineNumber":208,"sourceCode":"          !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(),\n    };","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/storage/domains/knowledge/inmemory.ts#L190-L226","documentation":"The target node has already been merged into another node (mergedInto is set). Merged nodes are tombstones — their content is owned by the merge target — so updating them is forbidden to avoid diverging from the terminal node.","triggerScenarios":"Calling updateNode({ id }) on a node that a previous mergeNodes(sourceId=id, targetId=...) call marked as merged, while its stale version still passes the version check (or the caller replayed an old update).","commonSituations":"A workflow captured the node before a merge happened elsewhere; retry logic re-applying an old update; agents sharing a knowledge store where one merged a duplicate into another.","solutions":["Resolve the merge chain and update the terminal (target) node instead of the tombstone","Skip the update if the node is merged (treat as already superseded)","Re-check freshness with getNode before updating, and handle mergedInto explicitly in your workflow"],"exampleFix":"// before\nawait store.updateNode({ id: sourceId, version, description });\n// after\nconst node = await store.getNode({ id: sourceId, resolutionScope: scope });\nconst target = node.mergedInto ?? node.id;\nawait store.updateNode({ id: target, version: (await store.getNode({ id: target, resolutionScope: scope })).version, description });","handlingStrategy":"type-guard","validationCode":"const node = await store.getNode({ id, resolutionScope: scope });\nif (node.mergedInto) throw new Error(`node ${id} was merged into ${node.mergedInto}; update the target instead`);","typeGuard":"function isMerged(node: KnowledgeNode): boolean {\n  return typeof node.mergedInto === 'string' && node.mergedInto.length > 0;\n}","tryCatchPattern":"try {\n  await store.updateNode({ id, version, ...patch });\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Cannot update merged knowledge node')) {\n    const terminal = await resolveTerminal(id);\n    await store.updateNode({ id: terminal.id, version: terminal.version, ...patch });\n  } else throw e;\n}","preventionTips":["Check mergedInto on the node before every update and follow the chain to the terminal","After merges, invalidate cached node references in long-running workflows","Design dedup flows so updates always target the merge destination","Track merge events in your app and re-map stored ids to terminal ids"],"tags":["knowledge-store","merged-node","tombstone","update"],"backgroundTag":"update-merged-record","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}