n8n-io/n8n · error · Error

Scenario "${scenario.name}" declares seed table "${table.nam

Error message

Scenario "${scenario.name}" declares seed table "${table.name}" that was not pre-seeded before the build; cannot bind its rows.

What it means

Thrown by reseedScenarioTables when a scenario declares a seed data table whose name has no entry in the tableIdsByName map produced by the pre-seed step. The harness pre-seeds all declared tables (creating them in the workspace) before the build, then reseeds per-scenario rows by name; a missing mapping means the table was never created, so rows cannot be bound. This is treated as a harness bug rather than user error.

Source

Thrown at packages/@n8n/instance-ai/evaluations/harness/seed-tables.ts:174

 * ids, just before that scenario executes (TRUST-311). Clears whatever rows a
 * prior scenario — or a build-time self-verification execution — left, then
 * inserts this scenario's declared rows, so each scenario runs against exactly
 * the state it declared (and scenarios may carry different rows for the same
 * table). `tableIdsByName` maps the declared table name to the real id created
 * before the build turn; a name missing from it means the table was never
 * pre-seeded, which is a harness bug, so throw rather than silently skip.
 */
export async function reseedScenarioTables(
	client: N8nClient,
	scenario: ExecutionScenario,
	threadId: string,
	tableIdsByName: Record<string, string>,
	logger: EvalLogger,
): Promise<void> {
	for (const table of scenario.seedDataTables ?? []) {
		const tableId = tableIdsByName[table.name];
		if (!tableId) {
			throw new Error(
				`Scenario "${scenario.name}" declares seed table "${table.name}" that was not pre-seeded before the build; cannot bind its rows.`,
			);
		}
		await client.seedDataTableRows(threadId, tableId, table.rows ?? []);
		logger.verbose(
			`    [${scenario.name}] reseeded data table "${table.name}" (${String((table.rows ?? []).length)} row(s))`,
		);
	}
}

/** Two seed tables bind the same way iff their columns + rows match (the id
 *  differs per declaration and is cosmetic under by-name seeding). */
function sameSeedTableShape(
	a: InstanceAiEvalSeedDataTable,
	b: InstanceAiEvalSeedDataTable,
): boolean {
	return (
		JSON.stringify({ columns: a.columns, rows: a.rows }) ===

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Ensure every scenario.seedDataTables[].name is included in the pre-seed pass that builds tableIdsByName (verify the same scenario list is used for both steps).
  2. Check upstream pre-seed logs for a skipped/failed creation of the named table.
  3. Confirm the name strings match exactly (case, whitespace) between the scenario declaration and the pre-seed map keys.

Example fix

// before — pre-seed only creates some names, reseed expects all
const tableIdsByName = preSeedTables(scenarioA.seedDataTables); // missing scenarioB's table
reseedScenarioTables(client, scenarioB, threadId, tableIdsByName, logger);

// after — pre-seed from the union of all scenarios
const allTables = [...scenarioA.seedDataTables, ...scenarioB.seedDataTables];
const tableIdsByName = preSeedTables(allTables);
reseedScenarioTables(client, scenarioB, threadId, tableIdsByName, logger);
Defensive patterns

Strategy: validation

Validate before calling

function allScenarioTablesPreSeeded(
  scenarios: { name: string; seedDataTables?: { name: string }[] }[],
  tableIdsByName: Record<string, string>,
): { ok: true } | { ok: false; missing: { scenario: string; table: string }[] } {
  const missing: { scenario: string; table: string }[] = [];
  for (const s of scenarios)
    for (const t of s.seedDataTables ?? [])
      if (!tableIdsByName[t.name]) missing.push({ scenario: s.name, table: t.name });
  return missing.length ? { ok: false, missing } : { ok: true };
}

const check = allScenarioTablesPreSeeded(allScenarios, tableIdsByName);
if (!check.ok) throw new Error(`pre-seed missing: ${JSON.stringify(check.missing)}`);

Type guard

null

Try / catch

try {
  await reseedScenarioTables(client, scenario, threadId, tableIdsByName, logger);
} catch (e) {
  if (e instanceof Error && /was not pre-seeded before the build/.test(e.message)) {
    // re-run pre-seed for the union of all scenario tables, then retry
  }
  throw e;
}

Prevention

When it happens

Trigger: The pre-seed step skipped a table name (e.g. due to a dedup collision where a different name won); the tableIdsByName map was built from a different scenario list than the one being reseeded; a race where the table creation failed silently upstream.

Common situations: Case authoring introduced a scenario with a new table name after the pre-seed map was computed; refactoring seed-table collection changed which names are pre-seeded; parallel scenario setup where one path dropped a table.

Related errors


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