pulumi/pulumi · error

could not read %s: %w

Error message

could not read %s: %w

What it means

ReadPackageManifest tries to os.ReadFile each recognized manifest (package.json, then package.yaml) in the given directory (sdk/nodejs/npm/manifest.go:35-43). Missing files are skipped, but any other read failure — permission denied, the path being a directory, I/O errors — is returned wrapped as "could not read <path>". It distinguishes real read failures from the benign not-exist case.

Source

Thrown at sdk/nodejs/npm/manifest.go:42

)

// PackageManifestNames are the filenames recognized as Node.js package manifests, in priority order. pnpm allows
// package.yaml as an alternative to package.json (see https://pnpm.io/package_json), and prefers package.json if both
// exist.
var PackageManifestNames = []string{"package.json", "package.yaml"}

// ReadPackageManifest reads the package manifest (package.json or package.yaml) from dir and returns the parsed
// contents along with the path of the file that was read. If both files exist, package.json is preferred. Returns an
// error wrapping os.ErrNotExist if neither file exists in dir.
func ReadPackageManifest(dir string) (map[string]any, string, error) {
	for _, name := range PackageManifestNames {
		path := filepath.Join(dir, name)
		content, err := os.ReadFile(path)
		if err != nil {
			if errors.Is(err, os.ErrNotExist) {
				continue
			}
			return nil, path, fmt.Errorf("could not read %s: %w", path, err)
		}
		data := map[string]any{}
		if err := unmarshalManifestBytes(name, content, &data); err != nil {
			return nil, path, fmt.Errorf("could not parse %s: %w", path, err)
		}
		return data, path, nil
	}
	return nil, "", fmt.Errorf("no package.json or package.yaml in %s: %w", dir, os.ErrNotExist)
}

func unmarshalManifestBytes(name string, content []byte, target any) error {
	m, _ := encoding.Detect(name)
	if m == nil {
		return fmt.Errorf("unsupported package manifest extension: %s", filepath.Ext(name))
	}
	return m.Unmarshal(content, target)
}

View on GitHub (pinned to 793f7b2e16)

Solutions

  1. Check permissions on the manifest path (`ls -la <path>`) and fix them (chmod/chown)
  2. If a directory is named package.json or package.yaml, rename or remove it
  3. Verify the file is a regular readable file, not a broken symlink or special file
  4. Run `pulumi` as a user with read access to the project directory

Example fix

// before
$ ls -la /app
-rw------- 1 root root 312 package.json
// after
$ sudo chown $(whoami) /app/package.json && chmod 644 /app/package.json
Defensive patterns

Strategy: try-catch

Validate before calling

info, err := os.Stat(manifestPath)
if err != nil {
	return fmt.Errorf("manifest not stat-able: %w", err)
}
if !info.Mode().IsRegular() {
	return fmt.Errorf("%s is not a regular file", manifestPath)
}
f, err := os.Open(manifestPath)
if err != nil {
	return fmt.Errorf("manifest unreadable (check permissions): %w", err)
}
f.Close()

Try / catch

data, path, err := npm.ReadPackageManifest(dir)
var pathErr *os.PathError
if errors.As(err, &pathErr) && !errors.Is(err, os.ErrNotExist) {
	// permission or I/O problem on pathErr.Path
	log.Warnf("cannot read manifest %s: %v; check permissions/ownership", pathErr.Path, err)
	return
}

Prevention

When it happens

Trigger: os.ReadFile on <dir>/package.json or <dir>/package.yaml fails with an error other than os.ErrNotExist: the file exists but is unreadable due to permissions, it is a directory named package.json, or a device/symlink I/O error occurs.

Common situations: A directory literally named `package.json` exists in the project root; restrictive file permissions after copying a repo as root or on Windows ACL issues; a broken mount or network drive where the manifest lives; SELinux/AppArmor blocking reads in containers.

Related errors


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