{"record":{"id":"57d6f7e922c37784","repo":"mastra-ai/mastra","slug":"knowledge-already-exists-record-id","errorCode":null,"errorMessage":"Knowledge already exists: ${record.id}","messagePattern":"Knowledge already exists: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/storage/domains/knowledge/inmemory.ts","lineNumber":342,"sourceCode":"\n  #appendKnowledge(input: AppendKnowledgeInput): KnowledgeRecord {\n    const node = nodeReferenceId(input.node);\n    const parent = this.#resolveTerminalNode(node);\n    if (!parent) throw new KnowledgeNotFoundError('node', node);\n    const scope = canonicalizeKnowledgeScope(input.scope);\n    assertKnowledgeScopeWithinCeiling(scope, input.maxScope);\n    const record: KnowledgeRecord = {\n      id: input.id ?? createKnowledgeUlid(),\n      node: parent.id,\n      text: input.text,\n      scope,\n      sourceThreadId: input.sourceThreadId,\n      capturedAt: new Date(),\n      when: input.when ? new Date(input.when) : undefined,\n      maxScope: input.maxScope,\n      metadata: input.metadata,\n    };\n    if (this.#db.knowledgeRecords.has(record.id)) throw new Error(`Knowledge already exists: ${record.id}`);\n    this.#db.knowledgeRecords.set(record.id, record);\n    this.#replaceMentions('record', record.id, record.text, input.resolutionScope, input.defaultScope);\n    parent.updatedAt = new Date();\n    this.#recordActivity('record-created', 'record', record.id, scope, input.sourceThreadId);\n    this.#enqueue('record', record.id, 'upsert', record.id, scope);\n    return cloneRecord(record);\n  }\n\n  async getKnowledge({\n    id,\n    includeDeleted = false,\n  }: {\n    id: string;\n    includeDeleted?: boolean;\n  }): Promise<KnowledgeRecord | null> {\n    const record = this.#db.knowledgeRecords.get(id);\n    if (!record || (record.deletedAt && !includeDeleted)) return null;\n    return cloneRecord(record);","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/storage/domains/knowledge/inmemory.ts#L324-L360","documentation":"#appendKnowledge generates a record ID (or takes input.id) and inserts into knowledgeRecords. If a record with that ID already exists, it throws to enforce record-ID uniqueness — duplicate insertion would corrupt the upsert/delete changelog. This only happens when callers supply their own input.id that collides.","triggerScenarios":"Calling appendKnowledge() with an explicit input.id equal to an existing record's ID; replaying the same append twice with deterministic IDs (e.g., derived from source content); concurrent appends using the same client-generated ID.","commonSituations":"Idempotent-retry logic reusing the same ID but not expecting a duplicate error; migration scripts importing records with original IDs into a store that already has some; test fixtures re-initialized without clearing the store.","solutions":["Omit input.id and let the storage generate a fresh ULID.","Before appending with a custom ID, check whether the store already holds it (listKnowledge / get by id) and skip or update instead.","Make retry logic idempotent: catch the duplicate and treat the existing record as the outcome.","Namespace custom IDs (source system + original id) to avoid collisions."],"exampleFix":"// before\nawait storage.appendKnowledge({ id: rec.id, node, text, scope }); // rec.id may already exist\n// after\nconst existing = await storage.getKnowledge(rec.id);\nif (!existing) await storage.appendKnowledge({ id: rec.id, node, text, scope });","handlingStrategy":"try-catch","validationCode":"const existing = await storage.listKnowledge({ /* filters */ });\nif (existing.records.some(r => r.id === desiredId)) skip = true;","typeGuard":null,"tryCatchPattern":"try {\n  await storage.appendKnowledge({ id: desiredId, node, text, scope });\n} catch (e) {\n  if (e.message.startsWith('Knowledge already exists')) {\n    return; // idempotent retry: record already present\n  }\n  throw e;\n}","preventionTips":["Omit input.id unless you need deterministic IDs for replay.","Namespace client-supplied IDs by source system.","Make import scripts idempotent by catching duplicates.","Clear store state between test runs."],"tags":["knowledge","duplicate","id-collision","append"],"backgroundTag":"duplicate-key-conflict","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}