hashicorp/terraform · error

failed to initialize cloudplugin cache directory

Error message

failed to initialize cloudplugin cache directory: %w

What it means

Thrown by CloudCommand.initPackagesCache when os.MkdirAll fails to create the cloudplugin cache directory (path.Join(WorkingDir.DataDir(), CloudPluginDataDir)). Terraform caches the cloudplugin binary there; if it cannot create the directory, the cloud subcommand cannot run.

Solutions

  1. Verify the data dir resolves correctly and is writable: `terraform -version` then check `echo $TF_DATA_DIR` / `$HOME`.
  2. Create and chmod the parent: `mkdir -p $HOME/.terraform.d && chmod u+w $HOME/.terraform.d`.
  3. Unset or fix TF_DATA_DIR if it points somewhere inappropriate.
  4. For containers, ensure HOME is set to a writable path and a writable volume is mounted there.

Example fix

// before: TF_DATA_DIR=/readonly-cache
// $ unset TF_DATA_DIR
// $ mkdir -p $HOME/.terraform.d && chmod 755 $HOME/.terraform.d
// after: terraform cloud / cloudplugin cache initializes successfully
Defensive patterns

Strategy: validation

Validate before calling

func dataDirWritable(dataDir string) error {
    if dataDir == "" { dataDir = filepath.Join(os.Getenv("HOME"), ".terraform.d") }
    if err := os.MkdirAll(dataDir, 0755); err != nil {
        return fmt.Errorf("cannot use data dir %s: %w", dataDir, err)
    }
    probe, err := os.CreateTemp(dataDir, ".perm-*")
    if err != nil { return err }
    probe.Close(); os.Remove(probe.Name())
    return nil
}

Prevention

When it happens

Trigger: The data directory (~/.terraform.d or $TF_DATA_DIR) or the cloudplugin subdirectory cannot be created — read-only filesystem, permission denied, or an invalid/empty path returned by WorkingDir.DataDir().

Common situations: TF_DATA_DIR points at a read-only or non-writable location; HOME unset in a container/service; running in a sandbox with no home write access; a parent path component is a file not a directory.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/6dd0f416e05fe9f1. Report an issue: GitHub.

Appendix: source

Thrown at internal/command/cloud.go:256

		diags = diags.Append(tfdiags.Sourceless(
			tfdiags.Warning,
			"Cloud plugin development overrides are in effect",
			detailMsg,
		))
	}
	log.Printf("[TRACE] plugin %q binary located at %q%s", version.ProductVersion, version.Path, cacheTraceMsg)
	c.pluginBinary = version.Path
	return diags
}

func (c *CloudCommand) initPackagesCache() (string, error) {
	packagesPath := path.Join(c.WorkingDir.DataDir(), CloudPluginDataDir)

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

	return packagesPath, nil
}

// Run runs the cloud command with the given arguments.
func (c *CloudCommand) Run(args []string) int {
	args = c.Meta.process(args)
	return c.realRun(args, c.Meta.Streams.Stdout.File, c.Meta.Streams.Stderr.File)
}

// Help returns help text for the cloud command.
func (c *CloudCommand) Help() string {
	helpText := new(bytes.Buffer)
	if exitCode := c.realRun([]string{}, helpText, io.Discard); exitCode != 0 {

View on GitHub (pinned to d32a084675)