hashicorp/terraform · error

failed to initialize stacksplugin cache directory: %w

Error message

failed to initialize stacksplugin cache directory: %w

What it means

Wrapped error from StacksCommand.initPackagesCache when os.MkdirAll(pluginPath, 0755) fails. After resolving the stacks plugin cache path (from .stackspluginpath or the default), if the directory does not exist or is not a directory, Terraform tries to create it. Failure means the cache directory cannot be created — almost always a permission or invalid-path problem.

Source

Thrown at internal/command/stacks.go:403

			pluginPath = defaultPluginPath
		} else {
			log.Printf("[TRACE] Failed to check the stacksplugin cache path store at '%s', using default '%s'", cacheStorePath, defaultPluginPath)
			// Use the default plugin cache path if there was an error checking the file
			pluginPath = defaultPluginPath
		}
	} else {
		data, err := os.ReadFile(cacheStorePath)
		if err != nil {
			return "", fmt.Errorf("failed to read stacks plugin stored path file: %w", err)
		}
		pluginPath = string(data)
	}

	if info, err := os.Stat(pluginPath); err != nil || !info.IsDir() {
		log.Printf("[TRACE] initialized stacksplugin cache directory at %q", pluginPath)
		err = os.MkdirAll(pluginPath, 0755)
		if err != nil {
			return "", fmt.Errorf("failed to initialize stacksplugin cache directory: %w", err)
		}
	} else {
		log.Printf("[TRACE] stacksplugin cache directory found at %q", pluginPath)
	}

	return pluginPath, nil
}

func (c *StacksCommand) storeStacksPluginPath(pluginCachePath string) error {
	f, err := os.Create(path.Join(c.WorkingDir.DataDir(), ".stackspluginpath"))
	if err != nil {
		return fmt.Errorf("failed to create stacks plugin stored path file: %w", err)
	}
	defer f.Close()
	f.WriteString(pluginCachePath)

	return nil
}

View on GitHub (pinned to c9def3e214)

Solutions

  1. Inspect the wrapped OS error for the exact path and reason (permission, not a directory, read-only).
  2. Fix the path recorded in .stackspluginpath or delete the file to fall back to the default.
  3. Ensure CLIConfigDir (~/.terraform.d) and its parent are writable.
  4. Run with appropriate filesystem permissions / writable mount in CI.

Example fix

// before: .stackspluginpath points at a read-only path
$ cat .terraform/.stackspluginpath
/readonly/plugins
// after
$ rm -f .terraform/.stackspluginpath
$ terraform stacks init   # recreates default writable cache dir
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: ensure the resolved stacks plugin cache path is creatable before stacks commands
package main

func preflightStacksCacheDir(path string) error {
	if path == "" { return fmt.Errorf("stacks plugin cache path is empty; set CLIConfigDir") }
	parent := filepath.Dir(path)
	if info, err := os.Stat(parent); err != nil {
		return fmt.Errorf("parent %s of cache dir missing: %w", parent, err)
	} else if !info.IsDir() {
		return fmt.Errorf("parent %s of cache dir is not a directory", parent)
	}
	return nil
}

Prevention

When it happens

Trigger: Running a stacks command where the resolved pluginPath is non-creatable: a parent path is a file (not a dir), permission denied on a parent, read-only filesystem, or pluginPath contains an invalid/relative segment. MkdirAll returns an OS error wrapped here.

Common situations: CLIConfigDir is unset making the default path empty/invalid; .stackspluginpath contains a bad path (typo, absolute path under a read-only mount); container/CI with read-only home; disk full; SELinux/AppArmor denying mkdir.

Related errors


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/e2d324124adbc22e. Report an issue: GitHub.