mastra-ai/mastra · error · Error

Knowledge node not found: ${value.node}

Error message

Knowledge node not found: ${value.node}

What it means

knowledge_append appends a record to an existing parent node; it never creates nodes. Before writing, the handler loads the node by the provided `node` ID and throws this error when the node is missing OR when it has been merged into another node (mergedInto set), since merged nodes are tombstones and no longer accept records. The error message includes the offending node identifier.

Source

Thrown at packages/memory/src/processors/observational-memory/subconscious/knowledge-write-tools.ts:71

    knowledge_append: createTool({
      id: 'knowledge_append',
      description: 'Append a scoped record to an existing node. Provenance and capture time are stamped by code.',
      inputSchema: {
        type: 'object',
        properties: {
          node: { type: 'string', minLength: 1 },
          text: { type: 'string', minLength: 1 },
          scope: scopeLevelSchema,
          when: { type: 'string' },
        },
        required: ['node', 'text'],
        additionalProperties: false,
      } satisfies JSONSchema7,
      execute: async input => {
        const value = input as { node: string; text: string; scope?: KnowledgeScopeLevel; when?: string };
        const store = await getStore(memory);
        const parent = await store.getNode(value.node);
        if (!parent || parent.mergedInto) throw new Error(`Knowledge node not found: ${value.node}`);
        requireVisible(parent.scope, options, 'Knowledge node');
        const scope = resolveWriteScope(options, value.scope);
        const when = value.when ? new Date(value.when) : undefined;
        if (when && Number.isNaN(when.getTime())) throw new Error('KnowledgeRecord when must be a valid date.');
        return store.appendKnowledge({
          node: parent.id,
          text: value.text,
          scope,
          sourceThreadId: options.sourceThreadId,
          when,
          maxScope: options.maxScope,
          resolutionScope: options.scope,
          defaultScope: expandKnowledgeScope(options.scope, options.defaultScope),
        });
      },
    }),
    knowledge_remove: createTool({
      id: 'knowledge_remove',

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Re-resolve the node by name via knowledge_read { name } or resolveNode within the current scope to get its current ID.
  2. If the node was merged, append to the surviving target node (follow mergedInto).
  3. Create the node first with knowledge_write_node_content when it genuinely doesn't exist.
  4. Instruct the agent to look up node IDs with knowledge_search/knowledge_read before appending.

Example fix

// before
await tools.knowledge_append.execute({ node: 'merged_or_missing_node', text: 'note' }, ctx);
// after
const node = await tools.knowledge_read.execute({ name: 'Deployment Guide' }, ctx);
if (node.found) await tools.knowledge_append.execute({ node: node.id, text: 'note' }, ctx);
Defensive patterns

Strategy: validation

Validate before calling

const parent = await tools.knowledge_read.execute({ id: nodeId }, ctx);
if (!parent.found || (parent as any).mergedInto) {
  throw new Error(`Cannot append: node ${nodeId} is missing or merged.`);
}

Type guard

function isAppendableNode(n: unknown): n is { id: string; mergedInto: undefined } {
  const x = n as { id?: string; mergedInto?: string | undefined };
  return typeof x?.id === 'string' && x.mergedInto === undefined;
}

Try / catch

try {
  return await curatorTools.knowledge_append.execute(args, {} as any);
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Knowledge node not found:')) {
    const nodeId = e.message.slice('Knowledge node not found: '.length);
    const live = await resolveNodeByName(nodeId);
    if (live) return curatorTools.knowledge_append.execute({ ...args, node: live.id }, {} as any);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling knowledge_append with a node ID that does not exist, was deleted, or was merged away by knowledge_merge_nodes; LLM inventing node IDs; reusing a cached ID after a merge.

Common situations: After a duplicate-node merge, agents still reference the source node's old ID; stale IDs from earlier sessions or other tenants; typo'd IDs copied from logs.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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