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 directory

View on GitHub (pinned to a0bd20f762)

Solutions

  1. Stop processes using the target directory (dev server, watchers, running lambdas locally) and retry
  2. Check ownership/permissions: the build user must be able to delete everything under targetDir
  3. Manually delete targetDir (rm -rf) to see the concrete OS error, then fix the root cause
  4. Ensure the previous build ran under the same user to avoid root-owned leftovers
  5. 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

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


AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30). Data as JSON: /api/errors/9a45486caa1ea4c5. Report an issue: GitHub.