hashicorp/terraform · error
failed to copy from to
Error message
failed to copy from %s to %s: %s
What it means
Thrown by reusingGetter.getWithGoGetter after the install target directory was created successfully but copy.CopyDir failed copying a previously-cached module install (prevDir) into the new install path (instPath). The first %s is the cache source dir, the second the new dest dir, the third the underlying copy error. It indicates a filesystem-level failure during the module-cache reuse optimization, not a network fetch problem.
Solutions
- Check read permission on the cached source dir and write permission on the install dir: ls -ld <prevDir> <instPath> and ensure the Terraform process owns or can write both.
- Free disk space or raise inode quota on the filesystem holding the module install directory (often .terraform).
- Clear the module cache / remove .terraform/modules and re-run terraform init so the package is fetched fresh instead of copied.
- If on a network/mounted filesystem, verify it is mounted read-write and not saturated; rerun init after remounting.
- On Windows, disable or except antivirus from scanning the cache dir, or close backup tools that lock files.
Example fix
# before: cache dir owned by root, terraform runs as user -> copy fails sudo chown -R $(whoami) .terraform/modules # then re-run terraform init
Defensive patterns
Strategy: try-catch
Validate before calling
// Before calling getWithGoGetter, verify prevDir readability and instPath writability:
// import "os"
// if fi, err := os.Stat(prevDir); err != nil || !fi.IsDir() {
// return fmt.Errorf("cache dir unavailable: %w", err)
// }
// if err := os.MkdirAll(filepath.Dir(instPath), 0o755); err != nil {
// return err
// } Try / catch
// Wrap the getter call; on copy failure, fall back to a fresh fetch by removing the cached prevDir entry and retrying once.
// err := g.getWithGoGetter(ctx, instPath, addr)
// if err != nil && strings.Contains(err.Error(), "failed to copy from") {
// delete(g, addr) // invalidate stale cache entry
// err = g.getWithGoGetter(ctx, instPath, addr) // retry once with fresh fetch
// } Prevention
- Run Terraform as the user that owns the .terraform/modules cache directory.
- Keep module cache on a writable local filesystem, not a read-only mount.
- Ensure adequate free disk/inodes on the working directory's volume before init.
- Avoid deleting or chowning the cache directory mid-run.
When it happens
Trigger: A second module call references the same packageAddr already downloaded earlier in the same run; the getter reuses it by copying prevDir -> instDir, but CopyDir returns an error (permissions, read-only source, dest on a full/read-only filesystem, or source dir vanished mid-copy).
Common situations: Module cache directory owned by root/another user while Terraform runs as non-root; NFS or mounted volume with permission restrictions; disk-full CI runner; antivirus/backup process locking files on Windows; cache dir manually deleted or rotated between detection and copy.
Related errors
- can not get working directory for current os platform
- can not read intermediate certificate from
- can not read leaf certificate from
- can not read leaf private key from
- can not read leafPassphraseBytes from
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/94c48b0e6b86604e.
Report an issue: GitHub.
Appendix: source
Thrown at internal/getmodules/getter.go:133
// the String method on a valid addrs.ModulePackage value.
//
// The errors returned by this function are those surfaced by the underlying
// go-getter library, which have very inconsistent quality as
// end-user-actionable error messages. At this time we do not have any
// reasonable way to improve these error messages at this layer because
// the underlying errors are not separately recognizable.
func (g reusingGetter) getWithGoGetter(ctx context.Context, instPath, packageAddr string) error {
var err error
if prevDir, exists := g[packageAddr]; exists {
log.Printf("[TRACE] getmodules: copying previous install of %q from %s to %s", packageAddr, prevDir, instPath)
err := os.Mkdir(instPath, os.ModePerm)
if err != nil {
return fmt.Errorf("failed to create directory %s: %s", instPath, err)
}
err = copy.CopyDir(instPath, prevDir)
if err != nil {
return fmt.Errorf("failed to copy from %s to %s: %s", prevDir, instPath, err)
}
} else {
log.Printf("[TRACE] getmodules: fetching %q to %q", packageAddr, instPath)
client := getter.Client{
Src: packageAddr,
Dst: instPath,
Pwd: instPath,
Mode: getter.ClientModeDir,
Detectors: goGetterNoDetectors, // our caller should've already done detection
Decompressors: goGetterDecompressors,
Getters: goGetterGetters,
Ctx: ctx,
}
err = client.Get()
if err != nil {
return errView on GitHub (pinned to d32a084675)