anomalyco/sst · error
failed to remove old directory: %w
Error message
failed to remove old directory: %w
What it means
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.
Source
Thrown at pkg/runtime/python/build.go:456
return err
}
if _, err := io.Copy(out, tr); err != nil {
out.Close()
return err
}
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 directoryView on GitHub (pinned to a0bd20f762)
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)
Defensive patterns
Strategy: try-catch
Validate before calling
if err := isWritable(targetDir); err != nil {
return fmt.Errorf("cannot replace %s: %w", targetDir, err)
} Try / catch
if err := processPackageArchive(...); err != nil {
var pathErr *os.PathError
if errors.As(err, &pathErr) && errors.Is(pathErr.Err, syscall.EACCES) {
// fix ownership/permissions or stop the locking process, then retry
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- failed to open archive: %w
- failed to move src directory contents: %w
- failed to rename directory: %w
- failed to walk extracted directory: %w
- failed to copy pyproject.toml for workspace package %s: %w
AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30).
Data as JSON: /api/errors/9a45486caa1ea4c5.
Report an issue: GitHub.