n8n-io/n8n · error · Error

Seed declares two agents with id "${duplicateAgentId}". Each

Error message

Seed declares two agents with id "${duplicateAgentId}". Each seeded agent is created at its pinned id, so the second would abort the restore — give them distinct ids

What it means

Thrown by remapSeedArtifactIds() when two agents in the seed declare the same id. Agents are restored by creating each at its pinned id, so a duplicate id would make the second create collide with the first and abort the whole restore. The harness refuses the fixture up front rather than fail mid-restore. Note: workflow duplicate NAMES are refused separately later (455), but ids are not — agent ids specifically carry this invariant because of the pinned-create semantics.

Source

Thrown at packages/@n8n/instance-ai/evaluations/harness/conversation-seed.ts:340

 * Agents get the id pass only: they are addressed by id, and an agent's name
 * appears inside skill prose, where a blanket rename would rewrite instructions
 * the case grades.
 *
 * The workflow name rewrite is applied to `messages` ONLY, never inside
 * `workflows[].nodes` — names are short and human ("Batch loop"), so a blanket
 * replace could hit a same-named node and silently alter the restored graph.
 */
export function remapSeedArtifactIds(seed: ConversationSeed): ConversationSeed {
	if (seed.workflows.length === 0 && seed.agents.length === 0) return seed;

	// Duplicates collapse in the id Set below, so both entries take ONE fresh id and
	// the restore's second `create` on that pinned id aborts the whole seed. Refuse
	// here rather than fail mid-restore — `workflows` has no such invariant either,
	// but its duplicate NAMES are already refused further down.
	const agentIds = seed.agents.map((agent) => agent.id);
	const duplicateAgentId = agentIds.find((id, index) => agentIds.indexOf(id) !== index);
	if (duplicateAgentId !== undefined) {
		throw new Error(
			`Seed declares two agents with id "${duplicateAgentId}". Each seeded agent is created at ` +
				'its pinned id, so the second would abort the restore — give them distinct ids',
		);
	}

	// Workflows and agents share one id space: a fresh id must miss every original,
	// or this sequential replace could rewrite a not-yet-processed artifact's id.
	const originalIds = new Set([
		...seed.workflows.map((workflow) => workflow.id),
		...seed.agents.map((agent) => agent.id),
	]);
	let serialized = JSON.stringify({
		messages: seed.messages,
		workflows: seed.workflows,
		agents: seed.agents,
	});
	// Longest id first, for the same reason the name pass below sorts: if one id were a
	// prefix of another ("abcdefgh" / "abcdefgh12"), rewriting the short one first would

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Give each agent in seed.agents a distinct id (≥8 chars — see 454).
  2. If the fixture was scrubbed from a real thread, re-derive ids so they are unique.
  3. Regenerate the inline seed rather than hand-editing it.

Example fix

// before
agents: [
  { id: 'agt-XXXX', name: 'A' },
  { id: 'agt-XXXX', name: 'B' },
]
// after
agents: [
  { id: 'agt-XXXXAAAA', name: 'A' },
  { id: 'agt-YYYYBBBB', name: 'B' },
]
Defensive patterns

Strategy: validation

Validate before calling

// Validate agent id uniqueness in the fixture before running.
function assertUniqueAgentIds(seed: ConversationSeed): void {
  const ids = seed.agents.map((a) => a.id);
  const dup = ids.find((id, i) => ids.indexOf(id) !== i);
  if (dup) throw new Error(`Duplicate agent id "${dup}" in seed fixture; give each agent a distinct id.`);
}

Prevention

When it happens

Trigger: A seed fixture (inline or scrubbed-from-real) contains two agent entries with the same `id` field. Often from copy-pasting an agent block and forgetting to mint a new id.

Common situations: Hand-authored fixture with a duplicated agent block; a scrubbed real trace where two agents happened to share an id after redaction.

Related errors


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