hashicorp/terraform · error
failed to create directory %s: %s
Error message
failed to create directory %s: %s
What it means
Returned by getWithGoGetter (getter.go:129) when, during reuse of a previously-downloaded module package, os.Mkdir(instPath) fails. The reusingGetter caches the first download of a given packageAddr; on subsequent references it tries to mkdir the destination and copy the cached tree rather than re-fetching. A failed mkdir indicates the install path cannot be created.
Source
Thrown at internal/getmodules/getter.go:129
// This function would ideally accept packageAddr as a value of type
// addrs.ModulePackage, but we can't do that because the addrs package
// depends on this package for package address parsing. Therefore we just
// use a string here but assume that the caller got that value by calling
// the String method on a valid addrs.ModulePackage value.
//
// The errors returned by this function are those surfaced by the underlying
// go-getter library, which have very inconsistent quality as
// end-user-actionable error messages. At this time we do not have any
// reasonable way to improve these error messages at this layer because
// the underlying errors are not separately recognizable.
func (g reusingGetter) getWithGoGetter(ctx context.Context, instPath, packageAddr string) error {
var err error
if prevDir, exists := g[packageAddr]; exists {
log.Printf("[TRACE] getmodules: copying previous install of %q from %s to %s", packageAddr, prevDir, instPath)
err := os.Mkdir(instPath, os.ModePerm)
if err != nil {
return fmt.Errorf("failed to create directory %s: %s", instPath, err)
}
err = copy.CopyDir(instPath, prevDir)
if err != nil {
return fmt.Errorf("failed to copy from %s to %s: %s", prevDir, instPath, err)
}
} else {
log.Printf("[TRACE] getmodules: fetching %q to %q", packageAddr, instPath)
client := getter.Client{
Src: packageAddr,
Dst: instPath,
Pwd: instPath,
Mode: getter.ClientModeDir,
Detectors: goGetterNoDetectors, // our caller should've already done detection
Decompressors: goGetterDecompressors,
Getters: goGetterGetters,
Ctx: ctx,View on GitHub (pinned to c9def3e214)
Solutions
- Check the OS error in the message: 'permission denied' → fix directory ownership/permissions on the .terraform directory; 'file exists' → remove the conflicting path; 'no space left' → free disk space.
- Ensure the working directory and .terraform/ are writable by the terraform process (common in CI/Docker — chown or run as the right user).
- Avoid concurrent terraform init/apply against the same working directory; serialize or use isolated workspaces.
- Run terraform init -upgrade or remove .terraform/modules to let it recreate the cache cleanly.
Example fix
# before — .terraform/modules owned by root, terraform runs as non-root # after — make the modules cache writable chown -R $(id -u):$(id -g) .terraform terraform init
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check the install path is creatable before calling go-getter reuse
func canCreateDir(p string) bool {
parent := filepath.Dir(p)
info, err := os.Stat(parent)
return err == nil && info.IsDir() && os.IsWritable... // best-effort
} Try / catch
if err := getter.Get(ctx, ...); err != nil {
if strings.Contains(err.Error(), "failed to create directory") {
// retry once after clearing the stale/partial path
os.RemoveAll(instPath)
err = getter.Get(ctx, ...)
}
return err
} Prevention
- Ensure the .terraform directory is writable by the terraform process (common CI/Docker issue).
- Do not run parallel terraform init against the same working directory.
- Run init -upgrade periodically to let the cache recreate cleanly.
When it happens
Trigger: Terraform references the same module source twice (so the reusingGetter cache hits) and the second install path cannot be created via os.Mkdir. The message reports instPath and the OS error.
Common situations: The .terraform/modules directory or target path is read-only, on a full disk, or has a conflicting non-directory file at instPath. Permission issues in CI containers. A path collision from parallel terraform runs writing to the same module cache. The parent directory was removed out from under the process.
Related errors
- failed to copy from %s to %s: %s
- failed to create local modules directory: %s
- error deleting workspace %s: %w
- cannot create temporary file to update credentials: %s
- could not write lock info for %q: %s
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/7a7c8f037c42761b.
Report an issue: GitHub.