{"record":{"id":"9d63ebc95796167e","repo":"eyaltoledano/claude-task-master","slug":"projectroot-is-required-for-getworktrees","errorCode":null,"errorMessage":"projectRoot is required for getWorktrees","messagePattern":"projectRoot is required for getWorktrees","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/tm-core/src/common/utils/git-utils.ts","lineNumber":350,"sourceCode":"}\n\n/**\n * Git worktree information\n */\nexport interface GitWorktree {\n\tpath: string;\n\tbranch: string | null;\n\thead: string;\n}\n\n/**\n * Get list of all git worktrees\n */\nexport async function getWorktrees(\n\tprojectRoot: string\n): Promise<GitWorktree[]> {\n\tif (!projectRoot) {\n\t\tthrow new Error('projectRoot is required for getWorktrees');\n\t}\n\n\ttry {\n\t\tconst { stdout } = await execAsync('git worktree list --porcelain', {\n\t\t\tcwd: projectRoot\n\t\t});\n\n\t\tconst worktrees: GitWorktree[] = [];\n\t\tconst lines = stdout.trim().split('\\n');\n\t\tlet current: Partial<GitWorktree> = {};\n\n\t\tfor (const line of lines) {\n\t\t\tif (line.startsWith('worktree ')) {\n\t\t\t\t// flush previous entry if present\n\t\t\t\tif (current.path) {\n\t\t\t\t\tworktrees.push({\n\t\t\t\t\t\tpath: current.path,\n\t\t\t\t\t\tbranch: current.branch || null,","sourceCodeStart":332,"sourceCodeEnd":368,"githubUrl":"https://github.com/eyaltoledano/claude-task-master/blob/c0c98d367c55296bfe69e65680625b6db437af02/packages/tm-core/src/common/utils/git-utils.ts#L332-L368","documentation":"getWorktrees() lists all git worktrees for a repository by running 'git worktree list --porcelain' with cwd set to projectRoot. Before doing anything it guards against a missing/empty projectRoot, throwing this error because a working directory is mandatory for the child git process.","triggerScenarios":"Calling getWorktrees(''), getWorktrees(undefined as any), getWorktrees(null as any), or passing an empty/undefined projectRoot — typically from the worktrees() wrapper that forwards an unset configuration value.","commonSituations":"Config file missing a project root; calling from code that never resolved the project root (e.g. running outside a detected repo and skipping the fallback to process.cwd()); refactored callers passing options objects instead of a string.","solutions":["Pass a valid absolute project root string: await getWorktrees('/path/to/repo')","Resolve the root before calling, e.g. const root = findProjectRoot() || process.cwd()","Check the config source that feeds the worktrees() wrapper so projectRoot is populated"],"exampleFix":"// before\nawait getWorktrees(config.projectRoot);\n// after\nconst root = config.projectRoot || findProjectRoot() || process.cwd();\nif (!root) throw new Error('Unable to resolve project root');\nawait getWorktrees(root);","handlingStrategy":"validation","validationCode":"if (!projectRoot || typeof projectRoot !== 'string') throw new Error('projectRoot must be a non-empty string before calling getWorktrees');","typeGuard":"function hasProjectRoot(root: unknown): root is string {\n  return typeof root === 'string' && root.trim().length > 0;\n}","tryCatchPattern":"try {\n  const worktrees = await getWorktrees(root);\n} catch (err) {\n  if (err.message.includes('projectRoot is required')) {\n    root = findProjectRoot() || process.cwd();\n    return retryGetWorktrees(root);\n  }\n  throw err;\n}","preventionTips":["Resolve and cache the project root once at app startup","Never pass config values straight through without an emptiness check","Prefer findProjectRoot()/process.cwd() fallbacks over raw config"],"tags":["git","argument-validation","worktrees"],"backgroundTag":"missing-required-argument","analyzedSha":"c0c98d367c55296bfe69e65680625b6db437af02","analyzedAt":"2026-08-29T02:56:26.071Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}