{"record":{"id":"cb6b6b1566d49660","repo":"hashicorp/terraform","slug":"cannot-read-directory-s","errorCode":null,"errorMessage":"Cannot read directory %s","messagePattern":"Cannot read directory (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/command/fmt.go","lineNumber":243,"sourceCode":"\t}\n\n\treturn diags\n}\n\nfunc (c *FmtCommand) processDir(path string, stdout io.Writer) tfdiags.Diagnostics {\n\tvar diags tfdiags.Diagnostics\n\n\tlog.Printf(\"[TRACE] terraform fmt: looking for files in %s\", path)\n\n\tentries, err := os.ReadDir(path)\n\tif err != nil {\n\t\tswitch {\n\t\tcase os.IsNotExist(err):\n\t\t\tdiags = diags.Append(fmt.Errorf(\"There is no configuration directory at %s\", path))\n\t\tdefault:\n\t\t\t// ReadDir does not produce error messages that are end-user-appropriate,\n\t\t\t// so we'll need to simplify here.\n\t\t\tdiags = diags.Append(fmt.Errorf(\"Cannot read directory %s\", path))\n\t\t}\n\t\treturn diags\n\t}\n\n\tfor _, info := range entries {\n\t\tname := info.Name()\n\t\tif configs.IsIgnoredFile(name) {\n\t\t\tcontinue\n\t\t}\n\t\tsubPath := filepath.Join(path, name)\n\t\tif info.IsDir() {\n\t\t\tif c.recursive {\n\t\t\t\tsubDiags := c.processDir(subPath, stdout)\n\t\t\t\tdiags = diags.Append(subDiags)\n\t\t\t}\n\n\t\t\t// We do not recurse into child directories by default because we\n\t\t\t// want to mimic the file-reading behavior of \"terraform plan\", etc,","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/command/fmt.go#L225-L261","documentation":"Emitted by terraform fmt's processDir in the default branch of the os.ReadDir error switch — i.e. ReadDir failed for any reason OTHER than the path not existing (the not-exist case is handled separately at fmt.go:239). The raw error is intentionally simplified because ReadDir's messages are not end-user friendly. The %s is the normalized target path.","triggerScenarios":"Running `terraform fmt <dir>` where the directory exists but cannot be read, most commonly due to insufficient POSIX permissions (missing read or execute bit on the directory). Also triggers on OS-level errors such as the path being a symlink loop, I/O errors from a failing disk, or the directory being a file/ special device instead of a directory.","commonSituations":"Directories created by another user with restrictive umask; running terraform as a non-owner; mounted filesystems that became read-only or failed; ACLs denying the current process. Containers where the bind-mounted directory lacks read access for the terraform process UID.","solutions":["Check and fix directory permissions: `chmod a+rx <dir>` (or grant the terraform process read+execute access).","Confirm the path is actually a directory and not a file/symlink: `ls -ld <dir>`.","If on a network/removable mount, verify the mount is healthy and read-write: `mount | grep <dir>`.","Run terraform as a user that owns or has been granted access to the directory."],"exampleFix":"# before\n$ terraform fmt ./configs   # dir exists but unreadable\n# after\n$ chmod a+rx ./configs\n$ terraform fmt ./configs","handlingStrategy":"validation","validationCode":"// Confirm the directory is readable+traversable by the current process.\nif err := unix.Access(dir, unix.R_OK|unix.X_OK); err != nil {\n    return fmt.Errorf(\"cannot read directory %q: %w; fix permissions first\", dir, err)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run terraform as a user that owns or has read+execute on the target directory.","Validate directory permissions in CI setup before the fmt step.","Avoid running fmt against directories on unhealthy/failing mounts."],"tags":["terraform-fmt","filesystem","permissions","io"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}