opentofu/opentofu · error
failed to read symlink %q: %w
Error message
failed to read symlink %q: %w
What it means
The walk's lstat reported the entry as a symlink, but the subsequent os.Readlink failed. On Unix, readlink fails with ENOENT only if the link itself was removed between lstat and readlink - the tree changed under the walk - or with EACCES if the containing directory is not readable. Windows adds junction/reparse-point edge cases.
Source
Thrown at internal/copy/copy_dir.go:102
return nil
}
errg.Go(func() error {
// we don't want to try and copy the same file over itself.
if eq, err := SameFile(path, dstPath); err != nil {
return fmt.Errorf("failed to check if files are the same: %w", err)
} else if eq {
return nil
}
// If the current path is a symlink, recreate the symlink relative to
// the dst directory
if info.Mode()&os.ModeSymlink == os.ModeSymlink {
target, err := os.Readlink(path)
if err != nil {
return fmt.Errorf("failed to read symlink %q: %w", path, err)
}
if err := os.Symlink(target, dstPath); err != nil {
return fmt.Errorf("failed to create symlink %q: %w", dstPath, err)
}
return nil
}
return copyFile(dstPath, path, info.Mode())
})
return nil
}
err = filepath.Walk(src, walkFn)
waitErr := errg.Wait()
return errors.Join(waitErr, err)
}
// copyFile copies the contents and mode of the file from src to dst.
func copyFile(dst, src string, mode os.FileMode) error {View on GitHub (pinned to 3561785c48)
Solutions
- Stabilize the source tree first (finish builds/cleanups, or copy from a snapshot)
- Retry CopyDir; single-entry races usually clear on a second pass
- On Windows, identify the failing reparse point and exclude or materialize it before copying
Defensive patterns
Strategy: retry
Try / catch
if err := copy.CopyDir(dst, src); err != nil {
if strings.Contains(err.Error(), "failed to read symlink") {
// entry vanished between walk and copy: rerun on a quiesced tree
err = copy.CopyDir(dst, src)
}
} Prevention
- Quiesce the source tree (finish builds/cleanups) before copying
- Copy symlink-heavy trees from snapshots rather than live directories
When it happens
Trigger: A symlink deleted concurrently with the copy (package managers, build cleanups); a symlink inside a directory whose read permission was revoked; Windows reparse points that readlink cannot handle.
Common situations: Copying node_modules/build trees while a tool prunes them; parallel processes managing the same source directory; cross-platform CI hitting Windows junctions.
Related errors
- failed to create symlink %q: %w
- failed to evaluate symlinks for source %q: %w
- error walking the path %q: %w
- failed to check if files are the same: %w
- failed to open source file %q: %w
AI-assisted analysis of opentofu/opentofu@3561785c48 (2026-08-15).
Data as JSON: /api/errors/c5b2089e6f3b6623.
Report an issue: GitHub.