{"record":{"id":"a4735c1d1369a345","repo":"mastra-ai/mastra","slug":"knowledge-node-already-exists-node-id","errorCode":null,"errorMessage":"Knowledge node already exists: ${node.id}","messagePattern":"Knowledge node already exists: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/storage/domains/knowledge/inmemory.ts","lineNumber":128,"sourceCode":"        throw new Error(`Merged knowledge node is not visible from scope: ${input.name}`);\n      }\n      return cloneNode(terminal);\n    }\n\n    const now = new Date();\n    const node: KnowledgeNode = {\n      id: input.id ?? crypto.randomUUID(),\n      type: 'node',\n      name: input.name.trim(),\n      kind: input.kind,\n      content: input.content,\n      description: input.description,\n      scope,\n      version: 1,\n      createdAt: now,\n      updatedAt: now,\n    };\n    if (this.#db.knowledgeNodes.has(node.id)) throw new Error(`Knowledge node already exists: ${node.id}`);\n    this.#db.knowledgeNodes.set(node.id, node);\n    this.#db.knowledgeNodeKeys.set(key, node.id);\n    this.#replaceMentions('node', node.id, node.content ?? '', input.resolutionScope ?? scope, scope);\n    this.#recordActivity('node-created', 'node', node.id, scope);\n    this.#enqueue('node', node.id, 'upsert', node.version, scope);\n    return cloneNode(node);\n  }\n\n  async getNode(id: string): Promise<KnowledgeNode | null> {\n    const node = this.#db.knowledgeNodes.get(id);\n    return node ? cloneNode(node) : null;\n  }\n\n  async getNodeByName({ name, scope }: { name: string; scope: KnowledgeScope }): Promise<KnowledgeNode | null> {\n    const id = this.#db.knowledgeNodeKeys.get(recordKey(name, scope));\n    if (!id) return null;\n    const node = this.#db.knowledgeNodes.get(id);\n    return node ? cloneNode(node) : null;","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/storage/domains/knowledge/inmemory.ts#L110-L146","documentation":"The store attempted to insert a newly built KnowledgeNode whose generated id is already present in the knowledgeNodes map. Because node ids are normally freshly generated, this indicates an id collision — typically from a caller-supplied id, deterministic id generation, or a corrupted/desynchronized in-memory database.","triggerScenarios":"Calling createNode() with input that produces a node.id already present in #db.knowledgeNodes (e.g. custom id generation, replaying a recorded create, or an in-memory DB rebuilt inconsistently so the name-key index missed the existing node).","commonSituations":"Importing/exporting knowledge data across store instances; replaying event logs; deterministic/test id generators reused across creations; seeding the store twice in the same process.","solutions":["Use a unique id (default generation) or check existence with getNode/list first and skip creation if present","If the existing node is equivalent, treat creation as idempotent: fetch and return the existing node instead","Rebuild or reseed the in-memory store so id and key indexes are consistent"],"exampleFix":"// before\nawait store.createNode({ id: 'node-1', name: 'policy', scope });\n// after\nconst existing = await store.getNode({ id: 'node-1', resolutionScope: scope }).catch(() => null);\nconst node = existing ?? await store.createNode({ name: 'policy', scope });","handlingStrategy":"validation","validationCode":"const dup = await store.listNodes?.({ scope });\nif (dup?.some(n => n.name === name)) throw new Error(`node '${name}' already exists in scope`);","typeGuard":"function isNodeAbsent(store: KnowledgeStore, id: string): boolean {\n  return !store.hasNode?.(id);\n}","tryCatchPattern":"try {\n  node = await store.createNode(input);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Knowledge node already exists')) {\n    node = await store.getNode({ id: extractId(e.message), resolutionScope: input.scope });\n  } else throw e;\n}","preventionTips":["Do not pass caller-supplied ids unless idempotent re-creation is intended","Make create flows idempotent: fetch-by-name first, create only if missing","Seed the store once; guard seed scripts with existence checks","Regenerate ids per creation; never reuse ids from exported snapshots without clearing the store"],"tags":["knowledge-store","duplicate-id","inmemory","idempotency"],"backgroundTag":"duplicate-resource-id","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}