hashicorp/terraform · error
failed to create local modules directory: %s
Error message
failed to create local modules directory: %s
What it means
Raised at the start of module installation when os.MkdirAll fails to create the local modules directory (the .terraform/modules path used to cache downloaded module sources). The wrapped %s is the OS-level mkdir error, typically a permission denial, a read-only filesystem, an invalid path, or insufficient space/inodes.
Source
Thrown at internal/command/meta_config.go:292
return body, diags
}
// installModules reads a root module from the given directory and attempts
// recursively to install all of its descendant modules.
//
// The given hooks object will be notified of installation progress, which
// can then be relayed to the end-user. The uiModuleInstallHooks type in
// this package has a reasonable implementation for displaying notifications
// via a provided cli.Ui.
func (m *Meta) installModules(ctx context.Context, rootDir, testsDir string, upgrade, installErrsOnly bool, hooks ...initwd.ModuleInstallHook) (abort bool, diags tfdiags.Diagnostics) {
ctx, span := tracer.Start(ctx, "install modules")
defer span.End()
rootDir = m.normalizePath(rootDir)
err := os.MkdirAll(m.modulesDir(), os.ModePerm)
if err != nil {
diags = diags.Append(fmt.Errorf("failed to create local modules directory: %s", err))
return true, diags
}
loader, err := m.initConfigLoader()
if err != nil {
diags = diags.Append(err)
return true, diags
}
initializer := func(rootMod *configs.Module, walker configs.ModuleWalker) (*configs.Config, tfdiags.Diagnostics) {
variables, diags := backendrun.ParseConstVariableValues(m.VariableValues, rootMod.Variables)
ctx, ctxDiags := terraform.NewContext(&terraform.ContextOpts{
Parallelism: 1,
})
diags = diags.Append(ctxDiags)
if diags.HasErrors() {
return nil, diags
}View on GitHub (pinned to c9def3e214)
Solutions
- Check the wrapped error: if it is a permission error, grant write access to the working directory (or TF_DATA_DIR).
- If TF_DATA_DIR is set, ensure the path exists and is writable, or unset it to use the default .terraform.
- Run init in a writable working directory.
- Free disk space / inodes if the filesystem is full.
Example fix
// before // terraform init -> 'failed to create local modules directory: permission denied' // after chmod -R u+w .terraform # or set a writable data dir: export TF_DATA_DIR=/tmp/tfdata && terraform init
Defensive patterns
Strategy: validation
Validate before calling
// Verify the modules directory is writable before running init
dir := ".terraform/modules"
if v := os.Getenv("TF_DATA_DIR"); v != "" {
dir = filepath.Join(v, "modules")
}
if err := os.MkdirAll(dir, 0o755); err != nil {
log.Fatalf("cannot write modules dir: %v", err)
} Prevention
- Ensure the working directory is writable by the user running terraform.
- If using TF_DATA_DIR, point it at a writable path.
- Run init in a writable working directory in containers/CI.
- Check disk space/inodes before large module downloads.
When it happens
Trigger: installModules calls os.MkdirAll(m.modulesDir(), os.ModePerm) and err!=nil. m.modulesDir() resolves to .terraform/modules under the working directory (or TF_DATA_DIR if set). Triggered by: read-only mount, no write permission on cwd, an invalid TF_DATA_DIR, a path whose parent doesn't exist, or a full disk.
Common situations: Running `terraform init` in a directory the process cannot write to (e.g. system path, mounted RO image); TF_DATA_DIR pointing to a non-writable or non-existent location; container running as non-root user without volume write perms; filesystem full.
Related errors
- error deleting workspace %s: %w
- Module installation was canceled by an interrupt signal.
- failed to prepare working directory: %w
- failed to create directory %s: %s
- root module not found. Please run terraform init
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/bbfc7f126799d650.
Report an issue: GitHub.