hasura/graphql-engine · error

failed to ensure create directory %q: %w

Error message

failed to ensure create directory %q: %w

What it means

ensureDirs runs os.MkdirAll(path, 0o755) for each path passed to it (called from Prepare before plugin install). If any MkdirAll fails — permission denied, a path component is an existing file, or an I/O error — this error wraps the failing path and the underlying OS error.

Source

Thrown at cli/plugins/util.go:51

	// windowsForbidden is taken from  https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file
	windowsForbidden = []string{
		"CON", "PRN", "AUX", "NUL", "COM1", "COM2",
		"COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2",
		"LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
	}
)

func isValidSHA256(s string) bool { return validSHA256.MatchString(s) }

// ensureDirs makes sure the paths created.
func ensureDirs(paths ...string) error {
	var op errors.Op = "plugins.ensureDirs"

	for _, p := range paths {
		err := os.MkdirAll(p, 0o755)
		if err != nil {
			return errors.E(op, fmt.Errorf("failed to ensure create directory %q: %w", p, err))
		}
	}

	return nil
}

// IsSafePluginName checks if the plugin Name is safe to use.
func IsSafePluginName(name string) bool {
	if !safePluginRegexp.MatchString(name) {
		return false
	}

	for _, forbidden := range windowsForbidden {
		if strings.EqualFold(forbidden, name) {
			return false
		}
	}

View on GitHub (pinned to 724551b9ae)

Solutions

  1. Check the path in the message: if a file exists where a directory is expected, move/remove it.
  2. Fix ownership/permissions: mkdir -p the directory yourself and chown it to the running user (sudo chown -R $(whoami) <dir>).
  3. If read-only (container/snap), point the plugin dir at a writable location via configuration.

Example fix

# before
$ plugin-cli install ... # EACCES on /usr/local/lib/plugins

# after
$ sudo mkdir -p /usr/local/lib/plugins && sudo chown -R $(whoami) /usr/local/lib/plugins
$ plugin-cli install ...
Defensive patterns

Strategy: try-catch

Validate before calling

for _, dir := range []string{pluginDir, binDir} {
	if fi, err := os.Stat(dir); err == nil && !fi.IsDir() {
		return fmt.Errorf("%s exists and is not a directory", dir)
	}
	if err := os.MkdirAll(dir, 0o755); err != nil {
		return fmt.Errorf("pre-create %s: %w", dir, err)
	}
}

Try / catch

if err := plugins.Prepare(...); err != nil {
	if errors.Is(err, fs.ErrPermission) {
		// prompt user to fix ownership or choose a user-writable dir
	}
}

Prevention

When it happens

Trigger: Prepare → ensureDirs hitting: a parent directory in the path owned by another user (EACCES), an existing regular file where a directory is expected (ENOTDIR), a read-only filesystem, or an invalid path string.

Common situations: Installing a plugin into a bin/plugins dir under $HOME with wrong ownership after running the CLI with sudo; a config file sitting where a directory should be; disk full or read-only mounts in containers.

Related errors


AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28). Data as JSON: /api/errors/f3942e0ca7b439d7. Report an issue: GitHub.