anomalyco/sst · error
failed to copy %s to %s: %w
Error message
failed to copy %s to %s: %w
What it means
Raised in syncPythonFiles (pkg/runtime/python/python.go:341) when copyFile fails while syncing a changed/new .py file from source into the artifact directory. copyFile wraps its own failures (mkdir, open source, create dest, io.Copy), so the cause chain tells you which low-level step failed — most often the source file was deleted mid-sync or the destination is unwritable.
Source
Thrown at pkg/runtime/python/python.go:341
// 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 {
return fmt.Errorf("failed to create directory for %s: %v", artifactPath, err)
}
if err := copyFile(sourcePath, artifactPath); err != nil {
return fmt.Errorf("failed to copy %s to %s: %w", sourcePath, artifactPath, err)
}
}
}
return nil
}
// flattenSrcLayout removes the "src/pkg" segment from paths that follow the
// PEP 517 src-layout convention (e.g., "pkg/src/pkg/module" -> "pkg/module").
// Only flattens when the directory after "src" matches the directory before it.
func flattenSrcLayout(filePath string) string {
parts := strings.Split(filePath, "/")
if len(parts) < 3 {
return filePath
}
for i := 0; i < len(parts)-1; i++ {
if parts[i] == "src" && i > 0 && i+1 < len(parts) && parts[i-1] == parts[i+1] {
flattened := append([]string{}, parts[:i]...)View on GitHub (pinned to a0bd20f762)
Solutions
- Read the wrapped cause: 'failed to open source file' means the source vanished — re-save/recreate the file or restart dev so the walk rescan picks current state; 'failed to create destination file'/'create directory' means fix artifact permissions or disk space
- Retry the operation — transient races usually resolve on the next sync trigger
- Normalize the environment: stop dev, remove the artifact dir, restart to force a clean full sync
Example fix
// before failed to copy handlers/user.py to .sst/artifacts/handlers/user.py: failed to open source file: no such file or directory // after (recreate or restore the file, then) git checkout -- handlers/user.py sst dev
Defensive patterns
Strategy: retry
Validate before calling
// confirm source file still exists just before copy
if _, err := os.Stat(sourcePath); err != nil {
return fmt.Errorf("source vanished before copy: %s", sourcePath)
} Try / catch
if err := copyFile(sourcePath, artifactPath); err != nil {
if errors.Is(err, fs.ErrNotExist) {
// file deleted mid-sync: rescan and retry once
return resyncAndRetry(sourcePath, artifactPath)
}
if errors.Is(err, fs.ErrPermission) {
return fixPermsAndRetry(artifactPath)
}
return err
} Prevention
- Let the watcher quiesce (single save) instead of rapid multi-file churn while dev syncs
- Exclude .sst from AV/indexer real-time scanning on Windows
- Keep artifact dirs user-writable
- If a sync error appears right after deleting a file, restart dev to refresh the scan
When it happens
Trigger: Source file deleted between the walk scan and the copy (racing editor/git operation); destination file locked or read-only; MkdirAll inside copyFile failing (disk full, permissions); io.Copy I/O error.
Common situations: Saving/deleting files rapidly during `sst dev` in workspace-layout Python projects; antivirus/indexers holding the destination file on Windows; read-only artifact dirs from container-built artifacts.
Related errors
- failed to open source file: %w
- failed to copy %s to %s: %w
- failed to copy workspace package %s: %w
- failed to copy directory %s: %w
- failed to copy file %s: %w
AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30).
Data as JSON: /api/errors/c377426f772aefa8.
Report an issue: GitHub.