anomalyco/sst · error

failed to read pyproject.toml for workspace package %s: %w

Error message

failed to read pyproject.toml for workspace package %s: %w

What it means

copyWorkspacePackagesForContainer ensures each workspace package's pyproject.toml exists at the destination so the container build can install the package. When the destination lacks the file, it reads the source pyproject.toml; a read failure there is wrapped with the package path. Later steps need this file, so the container build cannot proceed without it.

Source

Thrown at pkg/runtime/python/build.go:704

		// Resolve full path relative to workspace root
		fullPath := filepath.Join(workspaceRoot, pkgPath)
		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)
		}

View on GitHub (pinned to a0bd20f762)

Solutions

  1. Re-run the build without concurrent jobs touching the same output/workspace (serialize builds)
  2. Verify the pyproject.toml in the package path is a regular readable file (file path/to/pyproject.toml, ls -la)
  3. Restore the missing/broken pyproject.toml in the workspace package (git checkout -- packages/<pkg>/pyproject.toml)
  4. Fix permissions: chmod u+r on the file and u+rx on the package directory

Example fix

// before
// packages/shared exists but pyproject.toml is a dangling symlink
$ rm packages/shared/pyproject.toml
// after
cat > packages/shared/pyproject.toml <<'EOF'
[project]
name = "shared"
version = "0.1.0"
EOF
Defensive patterns

Strategy: validation

Validate before calling

for _, pkg := range workspacePackages {
	pp := filepath.Join(pkg.Path, "pyproject.toml")
	fi, err := os.Lstat(pp)
	if err != nil {
		log.Fatalf("%s missing in package %s", pp, pkg.Name)
	}
	if !fi.Mode().IsRegular() {
		log.Fatalf("%s is not a regular file (symlink/dir) in %s", pp, pkg.Name)
	}
	if _, err := os.ReadFile(pp); err != nil {
		log.Fatalf("%s unreadable: %v", pp, err)
	}
}

Type guard

func hasReadablePyproject(pkgPath string) bool {
	pp := filepath.Join(pkgPath, "pyproject.toml")
	fi, err := os.Stat(pp)
	if err != nil || !fi.Mode().IsRegular() {
		return false
	}
	_, err = os.ReadFile(pp)
	return err == nil
}

Try / catch

if err := deploy(); err != nil && strings.Contains(err.Error(), "failed to read pyproject.toml") {
	fmt.Println("restore the package's pyproject.toml and avoid concurrent builds over the same workspace")
	os.Exit(1)
}

Prevention

When it happens

Trigger: os.ReadFile(srcPyproject) fails even though os.Stat earlier saw it: file removed between stat and read (race/concurrent build), permissions changed, or the path is a directory/broken symlink.

Common situations: Two concurrent builds racing over the same workspace (one deletes the temp/package dir mid-copy); pyproject.toml replaced by a directory or symlink pointing nowhere; a package directory created without read permissions in CI.

Related errors


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