mastra-ai/mastra · error

Cannot merge a knowledge node into itself

Error message

Cannot merge a knowledge node into itself

What it means

mergeNodes was called with sourceId === targetId. Merging a node into itself is meaningless and would corrupt the merge chain, so the store rejects it immediately before any lookup.

Source

Thrown at packages/core/src/storage/domains/knowledge/inmemory.ts:250

    if (input.content !== undefined || input.name !== undefined || input.scope !== undefined) {
      this.#replaceMentions('node', input.id, updated.content ?? '', input.resolutionScope ?? scope, scope);
    }
    this.#recordActivity('node-updated', 'node', input.id, scope);
    const scopeChanged = knowledgeScopeKey(existing.scope) !== knowledgeScopeKey(scope);
    if (scopeChanged) {
      this.#enqueue('node', input.id, 'delete', createKnowledgeUlid(), existing.scope);
      for (const record of this.#db.knowledgeRecords.values()) {
        if (record.node !== input.id) continue;
        this.#enqueue('record', record.id, 'delete', createKnowledgeUlid(), record.scope);
        if (!record.deletedAt) this.#enqueue('record', record.id, 'upsert', createKnowledgeUlid(), record.scope);
      }
    }
    this.#enqueue('node', input.id, 'upsert', updated.version, scope);
    return cloneNode(updated);
  }

  async mergeNodes(input: { sourceId: string; targetId: string; sourceVersion: number }): Promise<KnowledgeNode> {
    if (input.sourceId === input.targetId) throw new Error('Cannot merge a knowledge node into itself');
    const source = this.#db.knowledgeNodes.get(input.sourceId);
    if (!source) throw new KnowledgeNotFoundError('node', input.sourceId);
    if (source.version !== input.sourceVersion) throw new KnowledgeConflictError(input.sourceId);
    const target = this.#resolveTerminalNode(input.targetId);
    if (!target) throw new KnowledgeNotFoundError('node', input.targetId);
    if (target.id === source.id) throw new Error('Cannot create a knowledge merge cycle');
    if (!isKnowledgeScopeVisible(target.scope, source.scope)) {
      throw new Error('Cannot merge a knowledge node into a target that is narrower than its source scope');
    }

    for (const [id, record] of this.#db.knowledgeRecords) {
      if (record.node === source.id) {
        this.#db.knowledgeRecords.set(id, { ...record, node: target.id });
        this.#enqueue('record', id, record.deletedAt ? 'delete' : 'upsert', createKnowledgeUlid(), record.scope);
      }
    }
    for (const [key, mentions] of this.#db.knowledgeMentions) {
      if (mentions.has(source.id)) {

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Guard the call site: skip merging when sourceId === targetId
  2. When deduplicating, exclude the source node id from candidate targets
  3. Fetch candidate targets by name and filter out the source before merging

Example fix

// before
await store.mergeNodes({ sourceId, targetId, sourceVersion });
// after
if (sourceId !== targetId) await store.mergeNodes({ sourceId, targetId, sourceVersion });
Defensive patterns

Strategy: validation

Validate before calling

if (sourceId === targetId) throw new Error('refusing to merge a node into itself');

Type guard

function isMergePairValid(sourceId: string, targetId: string): boolean {
  return sourceId !== targetId && sourceId.length > 0 && targetId.length > 0;
}

Try / catch

try {
  await store.mergeNodes({ sourceId, targetId, sourceVersion });
} catch (e) {
  if (e instanceof Error && e.message === 'Cannot merge a knowledge node into itself') return null;
  throw e;
}

Prevention

When it happens

Trigger: Calling mergeNodes({ sourceId: x, targetId: x, sourceVersion }) — usually from code that resolved target and source from the same variable, or a UI allowing the same node to be selected for both fields.

Common situations: Batch dedup scripts where the duplicate list accidentally includes the node itself; frontend dropdown not excluding the source node.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/9d002df57ecc6ebb. Report an issue: GitHub.