eyaltoledano/claude-task-master · error
Cannot create circular dependency: task ${parentIdNum} is al
Error message
Cannot create circular dependency: task ${parentIdNum} is already a subtask or dependent of task ${existingTaskIdNum} What it means
addSubtask uses isTaskDependentOn to detect whether attaching the existing task under the parent would create a cycle: if the parent is already a subtask of, or depends on, the task being converted, the hierarchy would become circular. The error names both IDs to help untangle the dependency graph.
Source
Thrown at scripts/modules/task-manager/add-subtask.js:79
const existingTask = data.tasks[existingTaskIndex];
// Check if task is already a subtask
if (existingTask.parentTaskId) {
throw new Error(
`Task ${existingTaskIdNum} is already a subtask of task ${existingTask.parentTaskId}`
);
}
// Check for circular dependency
if (existingTaskIdNum === parentIdNum) {
throw new Error(`Cannot make a task a subtask of itself`);
}
// Check if parent task is a subtask of the task we're converting
// This would create a circular dependency
if (isTaskDependentOn(data.tasks, parentTask, existingTaskIdNum)) {
throw new Error(
`Cannot create circular dependency: task ${parentIdNum} is already a subtask or dependent of task ${existingTaskIdNum}`
);
}
// Find the highest subtask ID to determine the next ID
const highestSubtaskId =
parentTask.subtasks.length > 0
? Math.max(...parentTask.subtasks.map((st) => st.id))
: 0;
const newSubtaskId = highestSubtaskId + 1;
// Clone the existing task to be converted to a subtask
newSubtask = {
...existingTask,
id: newSubtaskId,
parentTaskId: parentIdNum
};
View on GitHub (pinned to c0c98d367c)
Solutions
- Inspect the dependency graph of both tasks (task-master shows dependencies) to find the cycle.
- Remove the offending dependency or subtask relationship first, then retry the conversion.
- Choose a different parent task that does not depend on the candidate child.
- Restructure so the hierarchy is acyclic (e.g. convert the parent instead).
Example fix
// before
await addSubtask('2', '1'); // task 2 depends on task 1 → cycle
// after
// remove task 2's dependency on task 1 first, then:
await addSubtask('2', '1'); Defensive patterns
Strategy: validation
Validate before calling
const data = readJSON(tasksPath, projectRoot, tag);
const parent = data.tasks.find(t => t.id === parseInt(parentId, 10));
const child = data.tasks.find(t => t.id === parseInt(existingTaskId, 10));
if (parent && child && isTaskDependentOn(data.tasks, parent, child.id)) {
throw new Error(`Cycle: task ${parent.id} already depends on task ${child.id}`);
} Type guard
function createsCycle(parent, childId, deps = parent?.dependencies || []) {
return deps.includes(childId) || parent?.parentTaskId === childId;
} Try / catch
try {
await addSubtask(tasksPath, parentId, existingTaskId);
} catch (err) {
if (err.message.startsWith('Cannot create circular dependency')) {
// remove the offending dependency or pick a different parent
} else throw err;
} Prevention
- Visualize the dependency graph before restructuring hierarchies
- Run cycle-detection checks in scripts that batch-convert tasks
- Keep dependencies shallow; deep chains invite cycles
- Add CI checks that reject cyclic task graphs
When it happens
Trigger: Calling addSubtask(parentId, existingTaskId) where parentId is a subtask/dependent of existingTaskId — e.g. converting task A into a subtask of task B when B already depends on A.
Common situations: Complex dependency graphs built up over time, scripting batch conversions without cycle analysis, or users reorganizing tasks without visualizing dependencies.
Related errors
- Cannot make a task a subtask of itself
- Could not determine complete execution order for task ${task
- Invalid iterations: ${iterations}. Must be a positive intege
- Invalid format: ${options.format}. Valid formats are: text,
- Parent task with ID ${parentIdNum} not found
AI-assisted analysis of eyaltoledano/claude-task-master@c0c98d367c (2026-08-29).
Data as JSON: /api/errors/c601d7c99be59fc3.
Report an issue: GitHub.