n8n-io/n8n · error · Error

duplicate case slug(s) across data/workflows and data/agents

Error message

duplicate case slug(s) across data/workflows and data/agents: ${dupes.map((d) => d.fileSlug).join(', ')}

What it means

Thrown by the langtracer-push CLI after it concatenates workflow test cases (data/workflows) and agent eval test cases (data/agents) and detects that two or more cases resolve to the same fileSlug. The push refuses to continue because slug identity is what lang-tracer keys cases on, so duplicates would silently overwrite one another. The check is structural, not content-based.

Source

Thrown at packages/@n8n/instance-ai/evaluations/cli/langtracer-push.ts:187

	const suite = suites.find((s) => s.slug === args.suite || String(s.id) === args.suite);
	if (!suite) {
		const known = suites
			.map((s) => s.slug)
			.sort()
			.join(', ');
		throw new Error(`suite "${args.suite}" not found. Available: ${known || '(none)'}.`);
	}

	// Select disk cases: loader applies --filter/--exclude, --tier narrows by the
	// case's datasets (mirrors data/source.ts); then narrow to the exact slugs
	// from positional args + --changed (if either was given).
	const loaded = [
		...loadWorkflowTestCasesWithFiles(args.filter, args.exclude),
		...loadAgentEvalTestCasesWithFiles(args.filter, args.exclude),
	];
	const dupes = loaded.filter((c, i) => loaded.findIndex((o) => o.fileSlug === c.fileSlug) !== i);
	if (dupes.length > 0) {
		throw new Error(
			`duplicate case slug(s) across data/workflows and data/agents: ${dupes.map((d) => d.fileSlug).join(', ')}`,
		);
	}
	const tier = args.tier;
	const all = tier ? loaded.filter((c) => c.testCase.datasets.includes(tier)) : loaded;
	const exactSlugs = new Set([...args.slugs, ...(args.changed ? gitChangedSlugs() : [])]);
	const selected = exactSlugs.size > 0 ? all.filter((c) => exactSlugs.has(c.fileSlug)) : all;

	const missing = [...exactSlugs].filter((s) => !all.some((c) => c.fileSlug === s));
	if (missing.length > 0) {
		console.warn(`⚠ no data/workflows or data/agents case file for: ${missing.join(', ')}`);
	}
	if (selected.length === 0) {
		console.log('No cases selected — nothing to push.');
		return;
	}

	const [{ cases }, exported] = await Promise.all([

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Inspect the dupes list printed in the message and rename one of the colliding files (its slug derives from filename) so the two differ.
  2. If the cases are genuinely the same case, delete one and keep a single source of truth in the appropriate dataset.
  3. Run the case loader standalone to enumerate all slugs across data/workflows and data/agents before pushing, to catch collisions early.
Defensive patterns

Strategy: validation

Validate before calling

function assertUniqueSlugs(cases: { fileSlug: string }[]): void {
  const seen = new Set<string>();
  for (const c of cases) {
    if (seen.has(c.fileSlug)) throw new Error(`duplicate slug: ${c.fileSlug}`);
    seen.add(c.fileSlug);
  }
}
assertUniqueSlugs([...loadWorkflowTestCasesWithFiles(), ...loadAgentEvalTestCasesWithFiles()]);

Type guard

const hasFileSlug = (c: unknown): c is { fileSlug: string } =>
  typeof c === 'object' && c !== null && typeof (c as any).fileSlug === 'string';

Try / catch

try { /* langtracer-push */ } catch (e) {
  if (e instanceof Error && e.message.startsWith('duplicate case slug')) { /* rename file, retry */ }
  else throw e;
}

Prevention

When it happens

Trigger: Running `langtracer-push` while a slug exists in both data/workflows/<slug>.{json,ts} and data/agents/<slug>.{json,ts}; renaming a file so two paths collapse to the same slug; adding a new agent case that shadows a workflow case name.

Common situations: Cross-team naming collisions between workflow and agent eval datasets; a copy/paste of a case file into the sibling directory without renaming; tooling that derives slug from a title field that matches across datasets.

Related errors


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