{"record":{"id":"897134523a5e3e3f","repo":"n8n-io/n8n","slug":"seed-artifact-id-id-is-too-short-to-remap-saf","errorCode":null,"errorMessage":"Seed artifact id \"${id}\" is too short to remap safely (need ≥8 chars)","messagePattern":"Seed artifact id \"(.+?)\" is too short to remap safely \\(need ≥8 chars\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/instance-ai/evaluations/harness/conversation-seed.ts","lineNumber":364,"sourceCode":"\t// Workflows and agents share one id space: a fresh id must miss every original,\n\t// or this sequential replace could rewrite a not-yet-processed artifact's id.\n\tconst originalIds = new Set([\n\t\t...seed.workflows.map((workflow) => workflow.id),\n\t\t...seed.agents.map((agent) => agent.id),\n\t]);\n\tlet serialized = JSON.stringify({\n\t\tmessages: seed.messages,\n\t\tworkflows: seed.workflows,\n\t\tagents: seed.agents,\n\t});\n\t// Longest id first, for the same reason the name pass below sorts: if one id were a\n\t// prefix of another (\"abcdefgh\" / \"abcdefgh12\"), rewriting the short one first would\n\t// eat the long one's prefix and leave it with a derived id no later pass matches.\n\tfor (const id of [...originalIds].sort((a, b) => b.length - a.length)) {\n\t\t// Artifact ids are long random tokens; a short id would risk rewriting\n\t\t// unrelated substrings, so refuse instead of corrupting the seed.\n\t\tif (id.length < 8) {\n\t\t\tthrow new Error(`Seed artifact id \"${id}\" is too short to remap safely (need ≥8 chars)`);\n\t\t}\n\t\tlet newId = generateNanoId();\n\t\twhile (originalIds.has(newId)) newId = generateNanoId();\n\t\tserialized = serialized.replaceAll(id, newId);\n\t}\n\n\tconst remapped = ConversationSeedSchema.parse(jsonParse(serialized));\n\n\t// n8n itself allows duplicate workflow names, so a scrubbed real seed could\n\t// legitimately carry two. This harness can't take them: the rename below rewrites\n\t// mentions by matching the name text, so both workflows' mentions would collapse\n\t// onto the first one's new name and the history would point at the wrong workflow.\n\t// Refuse rather than mangle — a limit of the rewrite, not an n8n rule.\n\tconst names = remapped.workflows.map((workflow) => workflow.name);\n\tconst duplicate = names.find((name, index) => names.indexOf(name) !== index);\n\tif (duplicate !== undefined) {\n\t\tthrow new Error(\n\t\t\t`Seed declares two workflows named \"${duplicate}\". The harness rewrites seed workflow ` +","sourceCodeStart":346,"sourceCodeEnd":382,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/instance-ai/evaluations/harness/conversation-seed.ts#L346-L382","documentation":"Thrown by remapSeedArtifactIds() when a workflow or agent id in the seed is shorter than 8 characters. The remap rewrites ids with a global string replaceAll over the serialized seed; a short id risks matching unrelated substrings inside message text or other fields, corrupting the seed. The harness refuses rather than perform an unsafe rewrite. Artifact ids are expected to be long random tokens.","triggerScenarios":"A seed fixture whose workflow/agent id is a hand-typed short string (e.g. 'wf1', 'a'). The 8-char floor is a safety bound on the replaceAll-based remap, not an n8n rule.","commonSituations":"Hand-authored fixture using a mnemonic id; a placeholder id never replaced with a real nano id; truncation during scrubbing.","solutions":["Replace any short id with a real nano id or any token ≥8 characters that does not appear as a substring elsewhere in the seed.","When authoring fixtures, generate ids with the same generator the runtime uses (generateNanoId).","Avoid ids that are substrings of message text."],"exampleFix":"// before\nworkflows: [{ id: 'wf1', name: 'Report', ... }]\n// after\nworkflows: [{ id: 'wf_8Kq2pR9xT', name: 'Report', ... }]","handlingStrategy":"validation","validationCode":"// Validate id length before the remap runs.\nfunction assertIdsRemappable(seed: ConversationSeed): void {\n  const ids = [...seed.workflows.map((w) => w.id), ...seed.agents.map((a) => a.id)];\n  const tooShort = ids.find((id) => id.length < 8);\n  if (tooShort) throw new Error(`Artifact id \"${tooShort}\" is <8 chars; use a long random token so replaceAll is safe.`);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Author ids with generateNanoId (or any ≥8-char random token).","Add a fixture linter enforcing the 8-char floor at author time.","Avoid ids that appear as substrings of message text."],"tags":["seed-fixture","validation","id-remap"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}