{"record":{"id":"32381ea2ec391e2b","repo":"eyaltoledano/claude-task-master","slug":"either-existingtaskid-or-newsubtaskdata-must-be-pr","errorCode":null,"errorMessage":"Either existingTaskId or newSubtaskData must be provided","messagePattern":"Either existingTaskId or newSubtaskData must be provided","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/modules/task-manager/add-subtask.js","lineNumber":134,"sourceCode":"\t\t\tconst newSubtaskId = highestSubtaskId + 1;\n\n\t\t\t// Create the new subtask object\n\t\t\tnewSubtask = {\n\t\t\t\tid: newSubtaskId,\n\t\t\t\ttitle: newSubtaskData.title,\n\t\t\t\tdescription: newSubtaskData.description || '',\n\t\t\t\tdetails: newSubtaskData.details || '',\n\t\t\t\tstatus: newSubtaskData.status || 'pending',\n\t\t\t\tdependencies: newSubtaskData.dependencies || [],\n\t\t\t\tparentTaskId: parentIdNum\n\t\t\t};\n\n\t\t\t// Add to parent's subtasks\n\t\t\tparentTask.subtasks.push(newSubtask);\n\n\t\t\tlog('info', `Created new subtask ${parentIdNum}.${newSubtaskId}`);\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t'Either existingTaskId or newSubtaskData must be provided'\n\t\t\t);\n\t\t}\n\n\t\t// Write the updated tasks back to the file with proper context\n\t\twriteJSON(tasksPath, data, projectRoot, tag);\n\n\t\t// Note: Task file generation is no longer supported and has been removed\n\n\t\treturn newSubtask;\n\t} catch (error) {\n\t\tlog('error', `Error adding subtask: ${error.message}`);\n\t\tthrow error;\n\t}\n}\n\nexport default addSubtask;\n","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/eyaltoledano/claude-task-master/blob/c0c98d367c55296bfe69e65680625b6db437af02/scripts/modules/task-manager/add-subtask.js#L116-L152","documentation":"addSubtask supports two modes: convert an existing task (existingTaskId) or create a brand-new subtask (newSubtaskData). This error is thrown when neither argument is supplied, so there is no source for the subtask. It is a fail-fast guard before any file mutation.","triggerScenarios":"Calling addSubtask(parentId) with no existingTaskId and no newSubtaskData, or passing null/undefined for both.","commonSituations":"Programming errors in scripts that build options dynamically and drop the field, CLI parsers not forwarding the argument, or refactors that removed newSubtaskData accidentally.","solutions":["Pass an existingTaskId to convert an existing task, or","Pass a newSubtaskData object (e.g. { title, description, ... }) to create a new subtask.","Add argument validation in calling code before invoking addSubtask."],"exampleFix":"// before\nawait addSubtask('1'); // neither provided\n// after\nawait addSubtask('1', null, { title: 'New subtask', description: '...' });","handlingStrategy":"validation","validationCode":"function assertSubtaskSource(opts = {}) {\n  const hasExisting = opts.existingTaskId != null;\n  const hasNew = opts.newSubtaskData != null && typeof opts.newSubtaskData === 'object';\n  if (hasExisting === hasNew) {\n    throw new Error('Provide exactly one of existingTaskId or newSubtaskData');\n  }\n}","typeGuard":"function hasSubtaskSource(opts) {\n  return opts?.existingTaskId != null ||\n    (opts?.newSubtaskData != null && typeof opts.newSubtaskData === 'object');\n}","tryCatchPattern":"try {\n  await addSubtask(tasksPath, parentId, opts);\n} catch (err) {\n  if (err.message.includes('Either existingTaskId or newSubtaskData')) {\n    console.error('addSubtask requires existingTaskId or newSubtaskData');\n  } else throw err;\n}","preventionTips":["Validate option objects before calling addSubtask","Avoid building options dynamically without a final shape check","Document both call modes (convert vs create) in wrapper functions","Use exactOptionalPropertyTypes-style strictness in TS wrappers"],"tags":["validation","arguments","api-misuse","subtasks"],"backgroundTag":"missing-required-argument","analyzedSha":"c0c98d367c55296bfe69e65680625b6db437af02","analyzedAt":"2026-08-29T02:56:26.071Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}