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
- Re-resolve the node by name via knowledge_read { name } or resolveNode within the current scope to get its current ID.
- If the node was merged, append to the surviving target node (follow mergedInto).
- Create the node first with knowledge_write_node_content when it genuinely doesn't exist.
- 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
- Resolve nodes by name in the current scope instead of reusing cached IDs.
- After knowledge_merge_nodes, update all references to the surviving target ID.
- Create nodes explicitly with knowledge_write_node_content before appending.
- Instruct agents to read a node first when unsure of its ID.
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
- KnowledgeRecord not found: ${(input as { recordId: string })
- Plugin tool "${toolName}" is no longer available
- Cannot favorite: ${entityType} with id ${entityId} does not
- Cannot update merged knowledge node: ${input.id}
- SandboxNotReadyError: sandbox with id '${this.id}' is not re
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/c7affb59b11f0a09.
Report an issue: GitHub.