pulumi/pulumi · error

opening %s: %w

Error message

opening %s: %w

What it means

When appending a minimal [project] section to an existing pyproject.toml, os.OpenFile with O_APPEND|O_WRONLY failed. This typically means the file cannot be opened for writing, e.g. it does not actually exist, is read-only, or permissions block writes.

Source

Thrown at sdk/python/toolchain/uv.go:198

		}
		// pyproject.toml exists but has no [project]. If requirements.txt sits next to it, append a minimal
		// [project] section and merge the deps in.
		requirementsTxt := filepath.Join(existingPyprojectDir, "requirements.txt")
		if _, statErr := os.Stat(requirementsTxt); statErr != nil {
			if errors.Is(statErr, os.ErrNotExist) {
				return nil
			}
			return fmt.Errorf("error while looking for requirements.txt: %w", statErr)
		}
		name := projectName
		if name == "" {
			name = filepath.Base(existingPyprojectDir)
		}
		pyprojectPath := filepath.Join(existingPyprojectDir, "pyproject.toml")
		section := fmt.Sprintf("\n[project]\nname = %q\nversion = \"0.1.0\"\ndependencies = []\n", name)
		f, err := os.OpenFile(pyprojectPath, os.O_APPEND|os.O_WRONLY, 0)
		if err != nil {
			return fmt.Errorf("opening %s: %w", pyprojectPath, err)
		}
		if _, err := f.WriteString(section); err != nil {
			contract.IgnoreClose(f)
			return fmt.Errorf("appending [project] to %s: %w", pyprojectPath, err)
		}
		if err := f.Close(); err != nil {
			return fmt.Errorf("closing %s: %w", pyprojectPath, err)
		}
		return u.mergeRequirementsTxt(ctx, existingPyprojectDir, showOutput, infoWriter, errorWriter)
	}

	requirementsTxtDir, err := searchup(cwd, "requirements.txt")
	pyprojectTomlDir := cwd
	hasRequirementsTxt := false
	if err == nil {
		pyprojectTomlDir = requirementsTxtDir
		hasRequirementsTxt = true
	} else if !errors.Is(err, os.ErrNotExist) {

View on GitHub (pinned to 793f7b2e16)

Solutions

  1. Make pyproject.toml writable: chmod u+w <path>/pyproject.toml
  2. Run pulumi as the user who owns the project directory
  3. Manually add a [project] section (name, version, dependencies) to pyproject.toml so the append path is skipped
  4. Ensure the file exists and is a regular file, not a directory or dangling symlink

Example fix

// before
-r--r--r-- pyproject.toml
// after
$ chmod u+w pyproject.toml
Defensive patterns

Strategy: validation

Validate before calling

import os
path = "pyproject.toml"
assert os.path.isfile(path), f"{path} missing or not a file"
assert os.access(path, os.W_OK), f"{path} not writable: run chmod u+w {path}"

Try / catch

try {
    await runPulumi();
} catch (e) {
    if (String(e).includes("opening ") && String(e).includes("pyproject.toml")) {
        console.error("pyproject.toml not writable; fix file mode or run as file owner");
    }
    throw e;
}

Prevention

When it happens

Trigger: PrepareProject found a pyproject.toml without a [project] section and a requirements.txt next to it, then failed to open that pyproject.toml for appending (EACCES on read-only file, file deleted between searchup and open, EISDIR).

Common situations: pyproject.toml checked into git as read-only or with 444 permissions; running pulumi as a different user than the file owner; read-only container filesystem; build system resetting file mode.

Related errors


AI-assisted analysis of pulumi/pulumi@793f7b2e16 (2026-08-31). Data as JSON: /api/errors/c3465a0384a91baf. Report an issue: GitHub.