n8n-io/n8n · error · Error

Tool name "${RECALL_MEMORY_TOOL_NAME}" is reserved while epi

Error message

Tool name "${RECALL_MEMORY_TOOL_NAME}" is reserved while episodic memory is enabled.

What it means

Thrown by the Set node validator (v3.3+) for each assignment entry that is not an object. Every assignment must be a record with id, name, value, and type; a primitive or array entry is rejected and the loop continues to the next entry.

Source

Thrown at packages/@n8n/agents/src/runtime/loop/runtime-context.ts:198

	private createRecallMemoryToolForRun(
		persistence: AgentPersistenceOptions | undefined,
		existingTools: BuiltTool[],
		executionCounter?: AgentExecutionCounter,
	): BuiltTool | undefined {
		const { memory, episodicMemory } = this.config;
		if (
			!memory ||
			!episodicMemory ||
			!isEpisodicMemoryEnabled(episodicMemory) ||
			!hasEpisodicMemoryStore(memory)
		) {
			return undefined;
		}
		const scope = getEpisodicMemoryScope(persistence);
		if (!scope) return undefined;
		if (existingTools.some((tool) => tool.name === RECALL_MEMORY_TOOL_NAME)) {
			throw new Error(
				`Tool name "${RECALL_MEMORY_TOOL_NAME}" is reserved while episodic memory is enabled.`,
			);
		}
		return createRecallMemoryTool({
			memory,
			config: episodicMemory,
			scope,
			executionCounter,
			agentName: this.config.name,
		});
	}

	/**
	 * Merge tool-attached `systemInstruction` fragments into the agent's
	 * configured instructions, split by stability:
	 *
	 * - `instructions`: fragments from tools present for the life of the run
	 *   (base tools, deferred-tool controllers, the recall tool) plus the

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Replace the offending entry with a full object: { id, name, value, type }.
  2. Generate a stable id for each entry (e.g. a uuid or incrementing string).
  3. Remove the entry if it was added by mistake.

Example fix

// before — entry is a string
assignments: { assignments: ['status', { id: '2', name: 'ok', value: 1, type: 'number' }] }

// after
assignments: {
  assignments: [
    { id: '1', name: 'status', value: 'ok', type: 'string' },
    { id: '2', name: 'ok', value: 1, type: 'number' },
  ],
}
Defensive patterns

Strategy: type-guard

Validate before calling

function isRecord(v: unknown): v is Record<string, unknown> {
  return typeof v === 'object' && v !== null && !Array.isArray(v);
}

const valid = assignmentItems.every(isRecord);
if (!valid) throw new Error('Every assignment must be an object');

Type guard

function isAssignment(v: unknown): v is Record<string, unknown> {
  return typeof v === 'object' && v !== null && !Array.isArray(v);
}

Prevention

When it happens

Trigger: During iteration of parameters.assignments.assignments[], an entry fails isRecord (it is null, an array, or a primitive). The issue is reported at parameterPath parameters.assignments.assignments[index] and the loop continues.

Common situations: Passing a string id instead of an object; a partially-built assignment list with a stray primitive; an AI builder emitting shorthand entries.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/8bcdce80d837f6a5. Report an issue: GitHub.