n8n-io/n8n · error · PlanValidationError
Task "${task.id}" depends on unknown task "${depId}"
Error message
Task "${task.id}" depends on unknown task "${depId}" What it means
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.
Source
Thrown at packages/@n8n/instance-ai/src/planned-tasks/planned-task-service.ts:40
this.name = 'PlanValidationError';
}
}
function hasDuplicateIds(tasks: PlannedTask[]): boolean {
return new Set(tasks.map((task) => task.id)).size !== tasks.length;
}
function validateDependencies(tasks: PlannedTask[]): void {
if (hasDuplicateIds(tasks)) {
throw new PlanValidationError('Plan contains duplicate task IDs');
}
const knownIds = new Set(tasks.map((task) => task.id));
const byId = new Map(tasks.map((task) => [task.id, task]));
for (const task of tasks) {
for (const depId of task.deps) {
if (!knownIds.has(depId)) {
throw new PlanValidationError(`Task "${task.id}" depends on unknown task "${depId}"`);
}
}
if (task.kind === 'checkpoint') {
if (task.deps.length === 0) {
throw new PlanValidationError(
`Checkpoint task "${task.id}" must depend on at least one build-workflow task`,
);
}
const dependsOnBuildWorkflow = task.deps.some(
(depId) => byId.get(depId)?.kind === 'build-workflow',
);
if (!dependsOnBuildWorkflow) {
throw new PlanValidationError(
`Checkpoint task "${task.id}" must depend on at least one build-workflow task`,
);
}
}
}View on GitHub (pinned to 5ac6606e81)
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.
Example fix
// before: [{ id: 'a', deps: [] }, { id: 'b', deps: ['c'] }] // 'c' missing
// after: [{ id: 'a', deps: [] }, { id: 'b', deps: ['a'] }] Defensive patterns
Strategy: validation
Validate before calling
const ids = new Set(tasks.map(t => t.id));
for (const t of tasks) for (const dep of t.deps) {
if (!ids.has(dep)) throw new Error(`Task "${t.id}" depends on unknown task "${dep}"`);
} Type guard
function allDepsResolve(tasks: { id: string; deps: string[] }[]): boolean {
const ids = new Set(tasks.map(t => t.id));
return tasks.every(t => t.deps.every(d => ids.has(d)));
} Try / catch
try { await coordinator.createPlan(threadId, tasks, meta); }
catch (e) {
if (e instanceof PlanValidationError) {
// return message to LLM; do not rethrow non-validation errors
}
throw e;
} Prevention
- Normalize ids (trim, consistent case) before submission.
- When renaming a task, update all deps referencing it.
- Validate deps resolve locally before calling createPlan.
When it happens
Trigger: 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.
Common situations: LLM renames a task but forgets to update dependents; manual plan editing drops a task without cleaning deps; id casing/whitespace mismatch.
Related errors
- Plan contains duplicate task IDs
- Checkpoint task "${task.id}" must depend on at least one bui
- Plan contains a dependency cycle involving "${taskId}"
- Cannot decrease maxIterations when resuming a run. Expected
- Checkpoint for runId ${this.runId} has pending tool calls —
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/d98d24cd169782f6.
Report an issue: GitHub.