anomalyco/sst · error
failed to move src directory contents: %w
Error message
failed to move src directory contents: %w
What it means
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.
Source
Thrown at pkg/runtime/python/build.go:461
}
out.Close()
}
}
return nil
}
// moveExtractedPackage moves the extracted package to the correct location
func moveExtractedPackage(extractedDir, targetDir, baseName string) error {
// For src layout, flatten src/{package_name} to {package_name}
srcPath := filepath.Join(extractedDir, "src", baseName)
if _, err := os.Stat(srcPath); err == nil {
if err := os.RemoveAll(targetDir); err != nil {
return fmt.Errorf("failed to remove old directory: %w", err)
}
// Move src/{package_name} to target
if err := os.Rename(srcPath, targetDir); err != nil {
return fmt.Errorf("failed to move src directory contents: %w", err)
}
// Clean up extracted directory
if err := os.RemoveAll(extractedDir); err != nil {
return fmt.Errorf("failed to clean up extracted directory: %w", err)
}
} else {
// No src directory — check if package needs flattening
if shouldFlattenPackage(extractedDir) {
return flattenPackageToRoot(extractedDir, targetDir)
}
// Standard case: rename directory
if err := os.RemoveAll(targetDir); err != nil {
return fmt.Errorf("failed to remove old directory: %w", err)
}
if err := os.Rename(extractedDir, targetDir); err != nil {View on GitHub (pinned to a0bd20f762)
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)
Example fix
// before: rename across devices fails with EXDEV
os.Rename(srcPath, targetDir)
// after: fall back to copy when rename fails
if err := os.Rename(srcPath, targetDir); err != nil {
if err := copyDir(srcPath, targetDir); err != nil {
return fmt.Errorf("failed to move src directory contents: %w", err)
}
os.RemoveAll(srcPath)
} Defensive patterns
Strategy: try-catch
Validate before calling
sameDevice := func(a, b string) bool {
var s1, s2 syscall.Stat_t
if syscall.Stat(a, &s1) != nil || syscall.Stat(filepath.Dir(b), &s2) != nil {
return false
}
return s1.Dev == s2.Dev
}
if !sameDevice(extractedDir, targetDir) {
// use copy-then-delete instead of rename
} Try / catch
if err := processPackageArchive(...); err != nil {
var linkErr *os.LinkError
if errors.As(err, &linkErr) && linkErr.Err == syscall.EXDEV {
// fall back to copying the directory
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- failed to rename directory: %w
- failed to open archive: %w
- failed to remove old directory: %w
- failed to flatten %s structure: %w
- failed to move extracted package: %w
AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30).
Data as JSON: /api/errors/1091cc21a9d62ec6.
Report an issue: GitHub.