{"record":{"id":"1091cc21a9d62ec6","repo":"anomalyco/sst","slug":"failed-to-move-src-directory-contents-w","errorCode":null,"errorMessage":"failed to move src directory contents: %w","messagePattern":"failed to move src directory contents: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/runtime/python/build.go","lineNumber":461,"sourceCode":"\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\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\tif err := os.Rename(extractedDir, targetDir); err != nil {","sourceCodeStart":443,"sourceCodeEnd":479,"githubUrl":"https://github.com/anomalyco/sst/blob/a0bd20f762883e72a35caccb4896c42ce5b3f707/pkg/runtime/python/build.go#L443-L479","documentation":"After removing the old target in the src-layout path, os.Rename(srcPath, targetDir) moves src/{package_name} to its final location. If the rename fails the error is wrapped as \"failed to move src directory contents\". Renames fail across filesystem boundaries (EXDEV), when the destination exists, or on permission problems.","triggerScenarios":"extractedDir and targetDir are on different mounts/filesystems (os.Rename cannot cross devices), targetDir was partially recreated between RemoveAll and Rename, or a parent directory is not writable.","commonSituations":"Build artifacts in /tmp while the target lives on a Docker volume (different devices); two concurrent builds racing to install the same package; sandboxed CI runners restricting rename operations.","solutions":["Ensure extractedDir and targetDir share the same filesystem/volume (use a work dir next to the target)","Run only one build at a time for the same project to avoid races on targetDir","Verify parent directory write permissions for the build user","If cross-device moves are unavoidable, switch to a copy-then-delete strategy instead of rename","Retry after transient mount issues (e.g. EBUSY on network volumes)"],"exampleFix":"// before: rename across devices fails with EXDEV\nos.Rename(srcPath, targetDir)\n\n// after: fall back to copy when rename fails\nif err := os.Rename(srcPath, targetDir); err != nil {\n    if err := copyDir(srcPath, targetDir); err != nil {\n        return fmt.Errorf(\"failed to move src directory contents: %w\", err)\n    }\n    os.RemoveAll(srcPath)\n}","handlingStrategy":"try-catch","validationCode":"sameDevice := func(a, b string) bool {\n    var s1, s2 syscall.Stat_t\n    if syscall.Stat(a, &s1) != nil || syscall.Stat(filepath.Dir(b), &s2) != nil {\n        return false\n    }\n    return s1.Dev == s2.Dev\n}\nif !sameDevice(extractedDir, targetDir) {\n    // use copy-then-delete instead of rename\n}","typeGuard":null,"tryCatchPattern":"if err := processPackageArchive(...); err != nil {\n    var linkErr *os.LinkError\n    if errors.As(err, &linkErr) && linkErr.Err == syscall.EXDEV {\n        // fall back to copying the directory\n    }\n    return err\n}","preventionTips":["Extract into a temp dir on the same filesystem/volume as the final target","Avoid running concurrent builds that target the same install directory","Verify parent directory writability before moving","On Docker, keep build temp and output on the same mount"],"tags":["filesystem","rename","python","packaging"],"backgroundTag":"cross-device-rename","analyzedSha":"a0bd20f762883e72a35caccb4896c42ce5b3f707","analyzedAt":"2026-08-30T11:26:00.383Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}