{"record":{"id":"4c827e8506e6a7ed","repo":"eyaltoledano/claude-task-master","slug":"failed-to-move-file-from-oldpath-to-newpath","errorCode":null,"errorMessage":"Failed to move file from ${oldPath} to ${newPath}: ${error.message}","messagePattern":"Failed to move file from (.+?) to (.+?): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/tm-core/src/modules/storage/adapters/file-storage/file-operations.ts","lineNumber":258,"sourceCode":"\t */\n\tasync deleteFile(filePath: string): Promise<void> {\n\t\ttry {\n\t\t\tawait fs.unlink(filePath);\n\t\t} catch (error: any) {\n\t\t\tif (error.code !== 'ENOENT') {\n\t\t\t\tthrow new Error(`Failed to delete file ${filePath}: ${error.message}`);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Rename/move file\n\t */\n\tasync moveFile(oldPath: string, newPath: string): Promise<void> {\n\t\ttry {\n\t\t\tawait fs.rename(oldPath, newPath);\n\t\t} catch (error: any) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to move file from ${oldPath} to ${newPath}: ${error.message}`\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Copy file\n\t */\n\tasync copyFile(srcPath: string, destPath: string): Promise<void> {\n\t\ttry {\n\t\t\tawait fs.copyFile(srcPath, destPath);\n\t\t} catch (error: any) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to copy file from ${srcPath} to ${destPath}: ${error.message}`\n\t\t\t);\n\t\t}\n\t}\n","sourceCodeStart":240,"sourceCodeEnd":276,"githubUrl":"https://github.com/eyaltoledano/claude-task-master/blob/c0c98d367c55296bfe69e65680625b6db437af02/packages/tm-core/src/modules/storage/adapters/file-storage/file-operations.ts#L240-L276","documentation":"moveFile() uses fs.rename(oldPath, newPath) and wraps any failure into 'Failed to move file from <old> to <new>: <reason>'. rename(2) is atomic but fails across filesystem boundaries (EXDEV) and when source/destination are invalid, so the raw OS error is surfaced with both paths.","triggerScenarios":"moveFile invoked when the source does not exist (ENOENT), source or destination directory lacks permission (EACCES), old and new paths are on different devices/mounts (EXDEV), or newPath is a non-empty directory (ENOTEMPTY/EEXIST).","commonSituations":"Renaming a tag file where .taskmaster spans a Docker volume boundary (rename across mounts fails with EXDEV); the source file was never created; destination directory missing or unwritable; Windows file locking by another process.","solutions":["Verify the source file exists at oldPath (ENOENT is the most common cause) and create it first if the flow expects it.","If the error is EXDEV (cross-device link), copy then delete instead of rename: use copyFile followed by deleteFile.","Ensure the destination directory exists and is writable (mkdir -p + permissions) before moving.","Check for the destination being an existing non-empty directory and choose a different destination path or remove it."],"exampleFix":"// before\nawait fileOps.moveFile('/mnt/vol1/tasks.json', '/mnt/vol2/tasks.json'); // EXDEV\n// after\nawait fileOps.copyFile('/mnt/vol1/tasks.json', '/mnt/vol2/tasks.json');\nawait fileOps.deleteFile('/mnt/vol1/tasks.json');","handlingStrategy":"fallback","validationCode":"import { stat, access, constants } from 'fs/promises';\nimport path from 'path';\nexport async function canMoveFile(oldPath: string, newPath: string): Promise<boolean> {\n  try {\n    const s = await stat(oldPath);\n    if (!s.isFile()) return false;\n    await access(path.dirname(newPath), constants.W_OK);\n    return true;\n  } catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await fileOps.moveFile(oldPath, newPath);\n} catch (err: any) {\n  if (err.message.includes('EXDEV') || err.message.includes('cross-device')) {\n    // fallback: copy + delete across filesystem boundaries\n    await fileOps.copyFile(oldPath, newPath);\n    await fileOps.deleteFile(oldPath);\n    return;\n  }\n  if (err.message.startsWith('Failed to move file')) {\n    console.error(`Move failed: verify ${oldPath} exists and ${path.dirname(newPath)} is writable (${err.message})`);\n  }\n  throw err;\n}","preventionTips":["Keep old and new paths on the same filesystem/mount to avoid EXDEV.","Ensure the source file exists before rename-based flows (tag rename).","Pre-create and permission the destination directory.","Prefer copy+delete as a portable alternative when volumes differ."],"tags":["filesystem","rename","move","file-storage"],"backgroundTag":"file-rename-failed","analyzedSha":"c0c98d367c55296bfe69e65680625b6db437af02","analyzedAt":"2026-08-29T02:56:26.071Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}