anomalyco/sst · error

failed to delete %s: %v

Error message

failed to delete %s: %v

What it means

Raised in syncPythonFiles (pkg/runtime/python/python.go:318) when os.Remove cannot delete a stale .py file that exists in the artifact directory but no longer in the source tree (for legacy workspace layouts). Typical causes: read-only artifact files/dirs, the file having been recreated as a directory, or permission mismatch.

Source

Thrown at pkg/runtime/python/python.go:318

			}

			if !info.IsDir() && strings.HasSuffix(path, ".py") {
				artifactFiles[relPath] = info
			}

			return nil
		})
		if err != nil {
			return fmt.Errorf("failed to scan artifact files: %v", err)
		}
	}

	// Delete files in artifacts that no longer exist in source
	for relPath := range artifactFiles {
		if _, exists := sourceFiles[relPath]; !exists {
			artifactPath := filepath.Join(destDir, relPath)
			if err := os.Remove(artifactPath); err != nil {
				return fmt.Errorf("failed to delete %s: %v", artifactPath, err)
			}
		}
	}

	// Copy/update changed files
	for relPath, sourceInfo := range sourceFiles {
		sourcePath := filepath.Join(srcDir, relPath)
		artifactPath := filepath.Join(destDir, relPath)

		needsCopy := true
		if artifactInfo, exists := artifactFiles[relPath]; exists {
			if !sourceInfo.ModTime().After(artifactInfo.ModTime()) {
				needsCopy = false
			}
		}

		if needsCopy {
			if err := os.MkdirAll(filepath.Dir(artifactPath), 0755); err != nil {

View on GitHub (pinned to a0bd20f762)

Solutions

  1. Read the failing artifactPath in the message and `rm -f` it manually with sufficient privileges (or chown the artifact dir to your user)
  2. If it became a directory, remove it with `rm -rf`; restart `sst dev` so sync reruns
  3. If artifacts are root-owned from container builds, run `sudo chown -R $(whoami) .sst` or build as the same user

Example fix

// before
failed to delete .sst/artifacts/old_module.py: permission denied
// after
sudo rm -f .sst/artifacts/old_module.py
sst dev
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check stale artifact file is removable
artifactPath := filepath.Join(destDir, relPath)
if _, err := os.Lstat(artifactPath); err == nil {
    if err := os.Chmod(artifactPath, 0644); err != nil { /* surface unwritable artifact early */ }
}

Try / catch

if err := syncPythonFiles(src, dst); err != nil {
    var pe *fs.PathError
    if strings.Contains(err.Error(), "failed to delete") && errors.As(err, &pe) {
        os.RemoveAll(pe.Path) // force-remove with elevated/user perms
        return syncPythonFiles(src, dst)
    }
    return err
}

Prevention

When it happens

Trigger: Source .py file renamed/deleted while the artifact copy is read-only or owned by another user; artifact path now a non-empty directory; artifact filesystem mounted read-only.

Common situations: Renaming a module in a workspace-layout Python project while artifacts were built by a container/CI as root; NFS/bind-mounted artifact dirs with root-squash; git checkout leaving stale artifacts with different permissions.

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/e863faea70629bd2. Report an issue: GitHub.