{"record":{"id":"d4e50ed1e5e41c1e","repo":"hashicorp/terraform","slug":"failed-to-read-stacks-plugin-stored-path-file-w","errorCode":null,"errorMessage":"failed to read stacks plugin stored path file: %w","messagePattern":"failed to read stacks plugin stored path file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/command/stacks.go","lineNumber":394,"sourceCode":"func (c *StacksCommand) initPackagesCache() (string, error) {\n\tvar pluginPath string\n\tdefaultPluginPath := path.Join(c.CLIConfigDir, StacksPluginDataDir)\n\tcacheStorePath := path.Join(c.WorkingDir.DataDir(), \".stackspluginpath\")\n\n\tif _, err := os.Stat(cacheStorePath); err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\tlog.Printf(\"[TRACE] No stacksplugin cache path store at '%s`, using default '%s'\", cacheStorePath, defaultPluginPath)\n\t\t\t// Use the default plugin cache path if the file does not exist\n\t\t\tpluginPath = defaultPluginPath\n\t\t} else {\n\t\t\tlog.Printf(\"[TRACE] Failed to check the stacksplugin cache path store at '%s', using default '%s'\", cacheStorePath, defaultPluginPath)\n\t\t\t// Use the default plugin cache path if there was an error checking the file\n\t\t\tpluginPath = defaultPluginPath\n\t\t}\n\t} else {\n\t\tdata, err := os.ReadFile(cacheStorePath)\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"failed to read stacks plugin stored path file: %w\", err)\n\t\t}\n\t\tpluginPath = string(data)\n\t}\n\n\tif info, err := os.Stat(pluginPath); err != nil || !info.IsDir() {\n\t\tlog.Printf(\"[TRACE] initialized stacksplugin cache directory at %q\", pluginPath)\n\t\terr = os.MkdirAll(pluginPath, 0755)\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"failed to initialize stacksplugin cache directory: %w\", err)\n\t\t}\n\t} else {\n\t\tlog.Printf(\"[TRACE] stacksplugin cache directory found at %q\", pluginPath)\n\t}\n\n\treturn pluginPath, nil\n}\n\nfunc (c *StacksCommand) storeStacksPluginPath(pluginCachePath string) error {","sourceCodeStart":376,"sourceCodeEnd":412,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/command/stacks.go#L376-L412","documentation":"Thrown inside the stacks plugin path loader when os.ReadFile(cacheStorePath) fails for the .stackspluginpath file. Note the asymmetry: os.Stat already succeeded (we are in the else branch), so this only fires for a narrow window — file deleted between stat and read, permission denied on read, or an I/O error. The path comes from c.WorkingDir.DataDir() joined with `.stackspluginpath`.","triggerScenarios":"Another process deletes `.stackspluginpath` between the os.Stat and os.ReadFile calls; file mode denies read to the current user (chmod 000); filesystem I/O error (NFS hiccup, disk failure); symlink loop or dangling symlink that stat followed but read cannot.","commonSituations":"Concurrent `terraform init` and `terraform stacks` runs racing on the same data dir; permissions altered by a CI step between runs; mounted volume with intermittent I/O errors; `.terraform` dir restored from a tarball that lost ownership.","solutions":["Re-run `terraform init` to regenerate `.stackspluginpath` and the plugin cache.","Check permissions on the data dir and `.stackspluginpath`: `ls -la .terraform/`.","Avoid running multiple terraform commands concurrently in the same working directory.","Delete `.stackspluginpath` and let Terraform fall back to the default plugin path on next run."],"exampleFix":"# before: stale .stackspluginpath\n rm -f .terraform/.stackspluginpath\n terraform stacks <args>\n\n# after (regenerated)\n terraform init\n terraform stacks <args>","handlingStrategy":"validation","validationCode":"// Before reading .stackspluginpath, ensure exclusive access.\nf, err := os.OpenFile(cacheStorePath, os.O_RDWR, 0)\nif err != nil {\n    return \"\", nil // fall through to default path\n}\ndefer f.Close()\nif err := flock.Try(f.Fd()); err != nil {\n    return \"\", fmt.Errorf(\"another terraform process holds .stackspluginpath: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"data, err := os.ReadFile(cacheStorePath)\nif err != nil {\n    if os.IsNotExist(err) {\n        return defaultPluginPath, nil // file gone; use default\n    }\n    // transient: stat said it existed, read failed — log and fall back\n    log.Printf(\"[WARN] .stackspluginpath read failed (%v); using default %s\", err, defaultPluginPath)\n    return defaultPluginPath, nil\n}","preventionTips":["Never run multiple `terraform stacks` / `terraform init` concurrently in one working dir.","Use TF_DATA_DIR per concurrent pipeline job to isolate the cache.","Pin ownership of `.terraform/` to the runtime uid in containers.","Add `.stackspluginpath` to a clean checkout step rather than relying on stat/read races."],"tags":["terraform","stacks","plugin","filesystem","race","permissions"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}