{"record":{"id":"75b698b224e972a2","repo":"n8n-io/n8n","slug":"restore-was-asked-to-seed-string-agents-length","errorCode":null,"errorMessage":"Restore was asked to seed ${String(agents.length)} agent(s) but the response carried ${String(restored.agentIds.length)} — the backend likely predates agent seeding.","messagePattern":"Restore was asked to seed (.+?) agent\\(s\\) but the response carried (.+?) — the backend likely predates agent seeding\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/instance-ai/evaluations/clients/n8n-client.ts","lineNumber":795,"sourceCode":"\t): Promise<{\n\t\trestored: number;\n\t\tworkflowIds: string[];\n\t\tdataTableIds: string[];\n\t\tagentIds: string[];\n\t}> {\n\t\tconst body: Record<string, unknown> = { threadId, messages, workflows, dataTables, agents };\n\t\tif (options.uniquifyNames !== undefined) body.uniquifyNames = options.uniquifyNames;\n\t\tconst result = await this.fetch('/rest/instance-ai/eval/restore-thread', {\n\t\t\tmethod: 'POST',\n\t\t\tbody,\n\t\t\ttimeoutMs: RESTORE_THREAD_TIMEOUT_MS,\n\t\t});\n\t\tconst restored = RestoreThreadEnvelope.parse(result).data;\n\t\t// `agentIds` defaults to [] for backends that predate agent seeding, which\n\t\t// would read as \"restored fine, zero agents\" on a backend that just ignored\n\t\t// the field. If we asked for agents, insist they came back.\n\t\tif (agents.length > 0 && restored.agentIds.length !== agents.length) {\n\t\t\tthrow new Error(\n\t\t\t\t`Restore was asked to seed ${String(agents.length)} agent(s) but the response carried ${String(restored.agentIds.length)} — the backend likely predates agent seeding.`,\n\t\t\t);\n\t\t}\n\t\treturn restored;\n\t}\n\n\t/**\n\t * Reset an existing data table's rows to exactly `rows` (clear-then-insert),\n\t * for the per-scenario row seeding of a case that pre-created its tables\n\t * before the build turn (TRUST-311). Unlike `restoreThread` (which CREATES\n\t * tables), this targets a table that already exists by id, so a scenario can\n\t * declare its own row state without disturbing the table the built workflow\n\t * bound. `threadId` scopes the table to the run's project server-side.\n\t * POST /rest/instance-ai/eval/seed-data-table-rows\n\t */\n\tasync seedDataTableRows(\n\t\tthreadId: string,\n\t\ttableId: string,","sourceCodeStart":777,"sourceCodeEnd":813,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/instance-ai/evaluations/clients/n8n-client.ts#L777-L813","documentation":"restoreThread sends agents[] in the body and expects the response's agentIds to match in length. Because agentIds defaults to [] for backends that predate agent seeding, a mismatch would otherwise look like 'restored fine, zero agents'. The guard insists that if you asked for agents, you got them.","triggerScenarios":"Running eval restore against an n8n instance older than the agent-seeding feature; partial seeding where some agents failed to create silently.","commonSituations":"Version skew between eval client and n8n backend; an agent definition referencing a missing resource that the backend dropped without error.","solutions":["Upgrade the n8n instance to a version that supports agent seeding in restore-thread.","Inspect the backend response to see which agents were not seeded and why.","If running against an older backend, remove agents from the restore payload temporarily."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Pre-check backend capability before sending agents:\nconst caps = await client.unwrapRestData<{ agentSeeding?: boolean }>(\n  await client.fetch('/rest/instance-ai/eval/capabilities'));\nif (agents.length > 0 && !caps.agentSeeding)\n  throw new Error('backend does not support agent seeding; upgrade or omit agents');","typeGuard":"const hasAgentIds = (v: unknown): v is { agentIds: unknown[] } =>\n  typeof v === 'object' && v !== null && Array.isArray((v as any).agentIds);","tryCatchPattern":"try { await client.restoreThread({ ...body, agents }); }\ncatch (e) {\n  if (e instanceof Error && e.message.includes('predates agent seeding')) { /* drop agents or upgrade */ }\n  else throw e;\n}","preventionTips":["Pin backend version >= agent-seeding release when using agents in restore.","Log agentIds returned so mismatches are diagnosable.","Distinguish 'old backend' from 'partial failure' before retrying."],"tags":["eval","n8n-api","version-mismatch","agents"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}