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 nil

View on GitHub (pinned to a0bd20f762)

Solutions

  1. 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.
  2. Free disk space or raise the quota if the wrapped error is ENOSPC.
  3. Ensure the build output location is writable by the user running `sst deploy` (fix ownership: `sudo chown -R $USER .sst`).
  4. 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

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


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