hashicorp/terraform · error
cannot search
Error message
cannot search %s: %s
What it means
`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.
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.
Example fix
// before: broken symlink in plugin dir causes walk error $ terraform init Error: cannot search /home/u/.terraform.d/plugins/registry/old: no such file or directory // after: prune dead links $ find ~/.terraform.d/plugins -xtype l -print -delete $ terraform init
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check the plugin directory is traversable
if fi, err := os.Stat(baseDir); err != nil || !fi.IsDir() {
return nil, fmt.Errorf("plugin dir unusable: %w", err)
}
// Optionally prune dead symlinks before walking
filepath.Walk(baseDir, func(p string, info os.FileInfo, err error) error {
if err != nil { return err }
if info.Mode()&os.ModeSymlink != 0 {
if _, e := os.Stat(p); e != nil { os.Remove(p) }
}
return nil
}) Try / catch
// Recover from per-path walk errors and continue discovery
err := filepath.Walk(baseDir, func(fullPath string, info os.FileInfo, err error) error {
if err != nil {
log.Printf("[WARN] skipping unreadable plugin path %s: %s", fullPath, err)
return nil // skip this entry, keep walking
}
// ...normal handling...
return nil
}) Prevention
- 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.
When it happens
Trigger: `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.
Common situations: 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.
Related errors
- cannot create temporary file to update credentials
- Cannot read directory
- cannot read
- cannot set mode for credentials file
- could not write lock info for
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/6b16611a4ac1e9c1.
Report an issue: GitHub.
Appendix: source
Thrown at internal/getproviders/filesystem_search.go:51
// potentially keep their plugins in a non-standard location but use a
// symlink to help Terraform find them anyway.
originalBaseDir := baseDir
if finalDir, err := filepath.EvalSymlinks(baseDir); err == nil {
if finalDir != filepath.Clean(baseDir) {
log.Printf("[TRACE] getproviders.SearchLocalDirectory: using %s instead of %s", finalDir, baseDir)
}
baseDir = finalDir
} else {
// We'll eat this particular error because if we're somehow able to
// find plugins via baseDir below anyway then we'd rather do that than
// hard fail, but we'll log it in case it's useful for diagnosing why
// discovery didn't produce the expected outcome.
log.Printf("[TRACE] getproviders.SearchLocalDirectory: failed to resolve symlinks for %s: %s", baseDir, err)
}
err := filepath.Walk(baseDir, func(fullPath string, info os.FileInfo, err error) error {
if err != nil {
return fmt.Errorf("cannot search %s: %s", fullPath, err)
}
// There are two valid directory structures that we support here...
// Unpacked: registry.terraform.io/hashicorp/aws/2.0.0/linux_amd64 (a directory)
// Packed: registry.terraform.io/hashicorp/aws/terraform-provider-aws_2.0.0_linux_amd64.zip (a file)
//
// Both of these give us enough information to identify the package
// metadata.
fsPath, err := filepath.Rel(baseDir, fullPath)
if err != nil {
// This should never happen because the filepath.Walk contract is
// for the paths to include the base path.
log.Printf("[TRACE] getproviders.SearchLocalDirectory: ignoring malformed path %q during walk: %s", fullPath, err)
return nil
}
relPath := filepath.ToSlash(fsPath)
parts := strings.Split(relPath, "/")
View on GitHub (pinned to d32a084675)