{"record":{"id":"6b16611a4ac1e9c1","repo":"hashicorp/terraform","slug":"cannot-search-s-s","errorCode":null,"errorMessage":"cannot search %s: %s","messagePattern":"cannot search (.+?): (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/getproviders/filesystem_search.go","lineNumber":51,"sourceCode":"\t// potentially keep their plugins in a non-standard location but use a\n\t// symlink to help Terraform find them anyway.\n\toriginalBaseDir := baseDir\n\tif finalDir, err := filepath.EvalSymlinks(baseDir); err == nil {\n\t\tif finalDir != filepath.Clean(baseDir) {\n\t\t\tlog.Printf(\"[TRACE] getproviders.SearchLocalDirectory: using %s instead of %s\", finalDir, baseDir)\n\t\t}\n\t\tbaseDir = finalDir\n\t} else {\n\t\t// We'll eat this particular error because if we're somehow able to\n\t\t// find plugins via baseDir below anyway then we'd rather do that than\n\t\t// hard fail, but we'll log it in case it's useful for diagnosing why\n\t\t// discovery didn't produce the expected outcome.\n\t\tlog.Printf(\"[TRACE] getproviders.SearchLocalDirectory: failed to resolve symlinks for %s: %s\", baseDir, err)\n\t}\n\n\terr := filepath.Walk(baseDir, func(fullPath string, info os.FileInfo, err error) error {\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"cannot search %s: %s\", fullPath, err)\n\t\t}\n\n\t\t// There are two valid directory structures that we support here...\n\t\t// Unpacked: registry.terraform.io/hashicorp/aws/2.0.0/linux_amd64 (a directory)\n\t\t// Packed:   registry.terraform.io/hashicorp/aws/terraform-provider-aws_2.0.0_linux_amd64.zip (a file)\n\t\t//\n\t\t// Both of these give us enough information to identify the package\n\t\t// metadata.\n\t\tfsPath, err := filepath.Rel(baseDir, fullPath)\n\t\tif err != nil {\n\t\t\t// This should never happen because the filepath.Walk contract is\n\t\t\t// for the paths to include the base path.\n\t\t\tlog.Printf(\"[TRACE] getproviders.SearchLocalDirectory: ignoring malformed path %q during walk: %s\", fullPath, err)\n\t\t\treturn nil\n\t\t}\n\t\trelPath := filepath.ToSlash(fsPath)\n\t\tparts := strings.Split(relPath, \"/\")\n","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/getproviders/filesystem_search.go#L33-L69","documentation":"`SearchLocalDirectory` walks `baseDir` with `filepath.Walk`. The walk callback receives an `err` argument when the filesystem cannot descend into a path (permission denied, broken symlink, removed directory). That error is wrapped with the offending `fullPath` and surfaced. It is the catch-all for filesystem-level failures during local plugin discovery.","triggerScenarios":"`filepath.Walk` invokes its callback with a non-nil `err` for a given `fullPath`; the callback returns `fmt.Errorf(\"cannot search %s: %s\", fullPath, err)` at filesystem_search.go:51.","commonSituations":"Permission denied on a directory under `~/.terraform.d/plugins` or `-plugin-dir`; broken symlink in the plugin path; directory deleted during the walk; filesystem mounted read-only or NFS hiccup; stale leftover from a failed install.","solutions":["Check the `fullPath` named in the error and `ls -l` / `stat` it for permissions or symlink breakage.","Repair or remove broken symlinks: `find ~/.terraform.d/plugins -xtype l -delete`.","Fix ownership/permissions so the running user can traverse the directory (chmod/ chown).","Point `plugin_directory` in the CLI config at a clean, readable directory and re-run."],"exampleFix":"// before: broken symlink in plugin dir causes walk error\n$ terraform init\nError: cannot search /home/u/.terraform.d/plugins/registry/old: no such file or directory\n\n// after: prune dead links\n$ find ~/.terraform.d/plugins -xtype l -print -delete\n$ terraform init","handlingStrategy":"try-catch","validationCode":"// Pre-check the plugin directory is traversable\nif fi, err := os.Stat(baseDir); err != nil || !fi.IsDir() {\n    return nil, fmt.Errorf(\"plugin dir unusable: %w\", err)\n}\n// Optionally prune dead symlinks before walking\nfilepath.Walk(baseDir, func(p string, info os.FileInfo, err error) error {\n    if err != nil { return err }\n    if info.Mode()&os.ModeSymlink != 0 {\n        if _, e := os.Stat(p); e != nil { os.Remove(p) }\n    }\n    return nil\n})","typeGuard":null,"tryCatchPattern":"// Recover from per-path walk errors and continue discovery\nerr := filepath.Walk(baseDir, func(fullPath string, info os.FileInfo, err error) error {\n    if err != nil {\n        log.Printf(\"[WARN] skipping unreadable plugin path %s: %s\", fullPath, err)\n        return nil // skip this entry, keep walking\n    }\n    // ...normal handling...\n    return nil\n})","preventionTips":["Run `find <plugin-dir> -xtype l -delete` periodically to drop dead links.","Ensure the running user owns or can traverse the plugin directory.","Point `-plugin-dir` at a clean, dedicated directory.","Avoid NFS/network mounts for the plugin cache when possible."],"tags":["filesystem","local-plugins","permissions","symlink"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}