anomalyco/sst · error
failed to copy pyproject.toml for workspace package %s: %w
Error message
failed to copy pyproject.toml for workspace package %s: %w
What it means
During a container build of a Python function, SST copies each workspace package referenced by a relative path in requirements.txt into the build output. When the package directory already exists in the output but is missing its pyproject.toml, SST reads the source pyproject.toml and writes it into the destination; this error is returned when that os.WriteFile fails. It wraps the underlying OS error (permissions, disk full, destination being a directory, etc.).
Source
Thrown at pkg/runtime/python/build.go:707
if _, err := os.Stat(fullPath); err != nil {
slog.Warn("workspace package directory not found", "path", fullPath, "line", line)
continue
}
// Copy to artifact at the same relative path
destPath := filepath.Join(input.Out(), pkgPath)
if _, err := os.Stat(destPath); err == nil {
// Already exists — just ensure pyproject.toml is present for uv pip install
srcPyproject := filepath.Join(fullPath, "pyproject.toml")
destPyproject := filepath.Join(destPath, "pyproject.toml")
if _, err := os.Stat(srcPyproject); err == nil {
if _, err := os.Stat(destPyproject); err != nil {
data, readErr := os.ReadFile(srcPyproject)
if readErr != nil {
return fmt.Errorf("failed to read pyproject.toml for workspace package %s: %w", pkgPath, readErr)
}
if err := os.WriteFile(destPyproject, data, 0644); err != nil {
return fmt.Errorf("failed to copy pyproject.toml for workspace package %s: %w", pkgPath, err)
}
}
}
continue
}
if err := os.MkdirAll(filepath.Dir(destPath), 0755); err != nil {
return fmt.Errorf("failed to create directory for workspace package %s: %w", pkgPath, err)
}
// Preserve pyproject.toml and metadata for uv pip install
if err := copyDir(fullPath, destPath, skipBuildArtifacts); err != nil {
return fmt.Errorf("failed to copy workspace package %s: %w", pkgPath, err)
}
}
return nilView on GitHub (pinned to a0bd20f762)
Solutions
- Check the wrapped error: run `ls -la` on the destPath/pyproject.toml inside the .sst output — if it is a directory or root-owned, delete the stale .sst build directory and redeploy.
- Free disk space or raise the quota if the wrapped error is ENOSPC.
- Ensure the build output location is writable by the user running `sst deploy` (fix ownership: `sudo chown -R $USER .sst`).
- If a folder named pyproject.toml exists in the package, rename/remove it.
Example fix
// before $ sst deploy Error: failed to copy pyproject.toml for workspace package ./packages/core: open /path/.sst/.../pyproject.toml: permission denied // after $ rm -rf .sst $ sudo chown -R $USER . # or free disk space $ sst deploy
Defensive patterns
Strategy: validation
Validate before calling
const dest = path.join(buildOut, pkgPath, 'pyproject.toml');
if (fs.existsSync(dest) && fs.statSync(dest).isDirectory()) throw new Error(`destination ${dest} is a directory; clean .sst and redeploy`);
fs.accessSync(path.dirname(dest), fs.constants.W_OK); Type guard
function isWritableFileDest(p) { try { const s = fs.statSync(p); return !s.isDirectory(); } catch { return true; } } Try / catch
try {
await deploy();
} catch (e) {
if (/failed to copy pyproject.toml for workspace package/.test(e.message)) {
fs.rmSync('.sst', { recursive: true, force: true });
await deploy(); // retry after cleaning stale output
} else throw e;
} Prevention
- Don't run deploys with sudo or mixed users; keep one owning user for .sst
- Never name a file/dir `pyproject.toml` inside package source other than the manifest
- Monitor disk space on CI runners before deploy
- Clean .sst after interrupted Docker-based builds
When it happens
Trigger: os.WriteFile(destPyproject, data, 0644) fails inside copyWorkspacePackagesForContainer (input.IsContainer=true) when: the destination path destPath/pyproject.toml exists as a directory, the build output directory is read-only, or the disk is full/exceeds quota.
Common situations: Build output (.sst directory) left with stale artifacts owned by root from a Docker run; disk quota exceeded on CI runners; a directory literally named pyproject.toml accidentally committed inside the workspace package; output volume mounted read-only.
Related errors
- failed to remove old directory: %w
- failed to walk extracted directory: %w
- failed to create directory for workspace package %s: %w
- failed to copy workspace package %s: %w
- failed to scan source files: %v
AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30).
Data as JSON: /api/errors/909bf4aaf9554ccb.
Report an issue: GitHub.