{"record":{"id":"c5b2089e6f3b6623","repo":"opentofu/opentofu","slug":"failed-to-read-symlink-q-w","errorCode":null,"errorMessage":"failed to read symlink %q: %w","messagePattern":"failed to read symlink %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/copy/copy_dir.go","lineNumber":102,"sourceCode":"\n\t\t\treturn nil\n\t\t}\n\n\t\terrg.Go(func() error {\n\n\t\t\t// we don't want to try and copy the same file over itself.\n\t\t\tif eq, err := SameFile(path, dstPath); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to check if files are the same: %w\", err)\n\t\t\t} else if eq {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\t// If the current path is a symlink, recreate the symlink relative to\n\t\t\t// the dst directory\n\t\t\tif info.Mode()&os.ModeSymlink == os.ModeSymlink {\n\t\t\t\ttarget, err := os.Readlink(path)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to read symlink %q: %w\", path, err)\n\t\t\t\t}\n\n\t\t\t\tif err := os.Symlink(target, dstPath); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to create symlink %q: %w\", dstPath, err)\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn copyFile(dstPath, path, info.Mode())\n\t\t})\n\t\treturn nil\n\t}\n\terr = filepath.Walk(src, walkFn)\n\twaitErr := errg.Wait()\n\treturn errors.Join(waitErr, err)\n}\n\n// copyFile copies the contents and mode of the file from src to dst.\nfunc copyFile(dst, src string, mode os.FileMode) error {","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/opentofu/opentofu/blob/3561785c48c1ce615e7c50261bd351f26053efa2/internal/copy/copy_dir.go#L84-L120","documentation":"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.","triggerScenarios":"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.","commonSituations":"Copying node_modules/build trees while a tool prunes them; parallel processes managing the same source directory; cross-platform CI hitting Windows junctions.","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"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := copy.CopyDir(dst, src); err != nil {\n\tif strings.Contains(err.Error(), \"failed to read symlink\") {\n\t\t// entry vanished between walk and copy: rerun on a quiesced tree\n\t\terr = copy.CopyDir(dst, src)\n\t}\n}","preventionTips":["Quiesce the source tree (finish builds/cleanups) before copying","Copy symlink-heavy trees from snapshots rather than live directories"],"tags":["filesystem","symlink","copy","race","windows"],"backgroundTag":null,"analyzedSha":"3561785c48c1ce615e7c50261bd351f26053efa2","analyzedAt":"2026-08-15T23:27:16.226Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}