{"record":{"id":"7a7c8f037c42761b","repo":"hashicorp/terraform","slug":"failed-to-create-directory-s-s","errorCode":null,"errorMessage":"failed to create directory %s: %s","messagePattern":"failed to create directory (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/getmodules/getter.go","lineNumber":129,"sourceCode":"// This function would ideally accept packageAddr as a value of type\n// addrs.ModulePackage, but we can't do that because the addrs package\n// depends on this package for package address parsing. Therefore we just\n// use a string here but assume that the caller got that value by calling\n// the String method on a valid addrs.ModulePackage value.\n//\n// The errors returned by this function are those surfaced by the underlying\n// go-getter library, which have very inconsistent quality as\n// end-user-actionable error messages. At this time we do not have any\n// reasonable way to improve these error messages at this layer because\n// the underlying errors are not separately recognizable.\nfunc (g reusingGetter) getWithGoGetter(ctx context.Context, instPath, packageAddr string) error {\n\tvar err error\n\n\tif prevDir, exists := g[packageAddr]; exists {\n\t\tlog.Printf(\"[TRACE] getmodules: copying previous install of %q from %s to %s\", packageAddr, prevDir, instPath)\n\t\terr := os.Mkdir(instPath, os.ModePerm)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create directory %s: %s\", instPath, err)\n\t\t}\n\t\terr = copy.CopyDir(instPath, prevDir)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to copy from %s to %s: %s\", prevDir, instPath, err)\n\t\t}\n\t} else {\n\t\tlog.Printf(\"[TRACE] getmodules: fetching %q to %q\", packageAddr, instPath)\n\t\tclient := getter.Client{\n\t\t\tSrc: packageAddr,\n\t\t\tDst: instPath,\n\t\t\tPwd: instPath,\n\n\t\t\tMode: getter.ClientModeDir,\n\n\t\t\tDetectors:     goGetterNoDetectors, // our caller should've already done detection\n\t\t\tDecompressors: goGetterDecompressors,\n\t\t\tGetters:       goGetterGetters,\n\t\t\tCtx:           ctx,","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/getmodules/getter.go#L111-L147","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before — .terraform/modules owned by root, terraform runs as non-root\n\n# after — make the modules cache writable\nchown -R $(id -u):$(id -g) .terraform\nterraform init","handlingStrategy":"try-catch","validationCode":"// Pre-check the install path is creatable before calling go-getter reuse\nfunc canCreateDir(p string) bool {\n    parent := filepath.Dir(p)\n    info, err := os.Stat(parent)\n    return err == nil && info.IsDir() && os.IsWritable... // best-effort\n}","typeGuard":null,"tryCatchPattern":"if err := getter.Get(ctx, ...); err != nil {\n    if strings.Contains(err.Error(), \"failed to create directory\") {\n        // retry once after clearing the stale/partial path\n        os.RemoveAll(instPath)\n        err = getter.Get(ctx, ...)\n    }\n    return err\n}","preventionTips":["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."],"tags":["getmodules","go-getter","filesystem","permissions","modules"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}