{"record":{"id":"d98d24cd169782f6","repo":"n8n-io/n8n","slug":"task-task-id-depends-on-unknown-task-depid","errorCode":null,"errorMessage":"Task \"${task.id}\" depends on unknown task \"${depId}\"","messagePattern":"Task \"(.+?)\" depends on unknown task \"(.+?)\"","errorType":"validation","errorClass":"PlanValidationError","httpStatus":null,"severity":"error","filePath":"packages/@n8n/instance-ai/src/planned-tasks/planned-task-service.ts","lineNumber":40,"sourceCode":"\t\tthis.name = 'PlanValidationError';\n\t}\n}\n\nfunction hasDuplicateIds(tasks: PlannedTask[]): boolean {\n\treturn new Set(tasks.map((task) => task.id)).size !== tasks.length;\n}\n\nfunction validateDependencies(tasks: PlannedTask[]): void {\n\tif (hasDuplicateIds(tasks)) {\n\t\tthrow new PlanValidationError('Plan contains duplicate task IDs');\n\t}\n\n\tconst knownIds = new Set(tasks.map((task) => task.id));\n\tconst byId = new Map(tasks.map((task) => [task.id, task]));\n\tfor (const task of tasks) {\n\t\tfor (const depId of task.deps) {\n\t\t\tif (!knownIds.has(depId)) {\n\t\t\t\tthrow new PlanValidationError(`Task \"${task.id}\" depends on unknown task \"${depId}\"`);\n\t\t\t}\n\t\t}\n\t\tif (task.kind === 'checkpoint') {\n\t\t\tif (task.deps.length === 0) {\n\t\t\t\tthrow new PlanValidationError(\n\t\t\t\t\t`Checkpoint task \"${task.id}\" must depend on at least one build-workflow task`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst dependsOnBuildWorkflow = task.deps.some(\n\t\t\t\t(depId) => byId.get(depId)?.kind === 'build-workflow',\n\t\t\t);\n\t\t\tif (!dependsOnBuildWorkflow) {\n\t\t\t\tthrow new PlanValidationError(\n\t\t\t\t\t`Checkpoint task \"${task.id}\" must depend on at least one build-workflow task`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/instance-ai/src/planned-tasks/planned-task-service.ts#L22-L58","documentation":"Thrown as a PlanValidationError by validateDependencies (planned-task-service.ts:38-41) when a task's deps array references an id that is not present in the tasks list. The knownIds set is built from submitted task ids, so any typo or dangling reference is caught. Like other PlanValidationError throws, plan.tool.ts catches it and returns the message as a tool result for the LLM to revise.","triggerScenarios":"A task lists a dep id that was never defined, was deleted, or is misspelled; ids differ only by case ('Task-1' vs 'task-1'); a dep references a task from a different plan batch.","commonSituations":"LLM renames a task but forgets to update dependents; manual plan editing drops a task without cleaning deps; id casing/whitespace mismatch.","solutions":["Ensure every entry in each task.deps matches the id of another task in the same batch.","Normalize ids (trim, consistent case) before submission.","If a dep is no longer needed, remove it from deps rather than leaving a dangling reference.","Re-call the tool with the corrected graph as the error message instructs."],"exampleFix":"// before: [{ id: 'a', deps: [] }, { id: 'b', deps: ['c'] }]  // 'c' missing\n// after:  [{ id: 'a', deps: [] }, { id: 'b', deps: ['a'] }]","handlingStrategy":"validation","validationCode":"const ids = new Set(tasks.map(t => t.id));\nfor (const t of tasks) for (const dep of t.deps) {\n  if (!ids.has(dep)) throw new Error(`Task \"${t.id}\" depends on unknown task \"${dep}\"`);\n}","typeGuard":"function allDepsResolve(tasks: { id: string; deps: string[] }[]): boolean {\n  const ids = new Set(tasks.map(t => t.id));\n  return tasks.every(t => t.deps.every(d => ids.has(d)));\n}","tryCatchPattern":"try { await coordinator.createPlan(threadId, tasks, meta); }\ncatch (e) {\n  if (e instanceof PlanValidationError) {\n    // return message to LLM; do not rethrow non-validation errors\n  }\n  throw e;\n}","preventionTips":["Normalize ids (trim, consistent case) before submission.","When renaming a task, update all deps referencing it.","Validate deps resolve locally before calling createPlan."],"tags":["planned-tasks","validation","plan-graph","dependencies","llm-retryable"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}