{"record":{"id":"9a45486caa1ea4c5","repo":"anomalyco/sst","slug":"failed-to-remove-old-directory-w","errorCode":null,"errorMessage":"failed to remove old directory: %w","messagePattern":"failed to remove old directory: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/runtime/python/build.go","lineNumber":456,"sourceCode":"\t\t\t\treturn err\n\t\t\t}\n\t\t\tif _, err := io.Copy(out, tr); err != nil {\n\t\t\t\tout.Close()\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tout.Close()\n\t\t}\n\t}\n\treturn nil\n}\n\n// moveExtractedPackage moves the extracted package to the correct location\nfunc moveExtractedPackage(extractedDir, targetDir, baseName string) error {\n\t// For src layout, flatten src/{package_name} to {package_name}\n\tsrcPath := filepath.Join(extractedDir, \"src\", baseName)\n\tif _, err := os.Stat(srcPath); err == nil {\n\t\tif err := os.RemoveAll(targetDir); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to remove old directory: %w\", err)\n\t\t}\n\n\t\t// Move src/{package_name} to target\n\t\tif err := os.Rename(srcPath, targetDir); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to move src directory contents: %w\", err)\n\t\t}\n\n\t\t// Clean up extracted directory\n\t\tif err := os.RemoveAll(extractedDir); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to clean up extracted directory: %w\", err)\n\t\t}\n\t} else {\n\t\t// No src directory — check if package needs flattening\n\t\tif shouldFlattenPackage(extractedDir) {\n\t\t\treturn flattenPackageToRoot(extractedDir, targetDir)\n\t\t}\n\n\t\t// Standard case: rename directory","sourceCodeStart":438,"sourceCodeEnd":474,"githubUrl":"https://github.com/anomalyco/sst/blob/a0bd20f762883e72a35caccb4896c42ce5b3f707/pkg/runtime/python/build.go#L438-L474","documentation":"In moveExtractedPackage's src-layout branch, before renaming src/{package_name} into place, the old target directory is removed with os.RemoveAll. If that removal fails, the error is wrapped as \"failed to remove old directory\". Typically the target path is locked by another process, is on a read-only mount, or contains files the build user cannot delete.","triggerScenarios":"os.RemoveAll(targetDir) fails because a file inside targetDir is open/locked (e.g. a running dev server importing the package), the directory sits on a read-only or full filesystem, or permission bits prevent deletion.","commonSituations":"sst dev is running while a rebuild tries to replace the installed package; the previous build ran as root and left root-owned files; a container volume keeps files busy; leftover .pyc files owned by another user.","solutions":["Stop processes using the target directory (dev server, watchers, running lambdas locally) and retry","Check ownership/permissions: the build user must be able to delete everything under targetDir","Manually delete targetDir (rm -rf) to see the concrete OS error, then fix the root cause","Ensure the previous build ran under the same user to avoid root-owned leftovers","Check the mount is writable and has free space (mount | grep, df -h)"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if err := isWritable(targetDir); err != nil {\n    return fmt.Errorf(\"cannot replace %s: %w\", targetDir, err)\n}","typeGuard":null,"tryCatchPattern":"if err := processPackageArchive(...); err != nil {\n    var pathErr *os.PathError\n    if errors.As(err, &pathErr) && errors.Is(pathErr.Err, syscall.EACCES) {\n        // fix ownership/permissions or stop the locking process, then retry\n    }\n    return err\n}","preventionTips":["Stop dev servers/watchers that import the package before rebuilding","Always build under the same (non-root) user","Verify write permissions on the install target before starting a build","Monitor disk space on the build volume"],"tags":["filesystem","permissions","python","packaging"],"backgroundTag":"permission-denied","analyzedSha":"a0bd20f762883e72a35caccb4896c42ce5b3f707","analyzedAt":"2026-08-30T11:26:00.383Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}