{"record":{"id":"a01337937f4f2c1a","repo":"dagger/dagger","slug":"too-many-links","errorCode":null,"errorMessage":"too many links","messagePattern":"too many links","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/contenthash/path.go","lineNumber":18,"sourceCode":"// This code mostly comes from <https://github.com/cyphar/filepath-securejoin>.\n\n// Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved.\n// Copyright (C) 2017-2024 SUSE LLC. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage contenthash\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/pkg/errors\"\n)\n\nvar errTooManyLinks = errors.New(\"too many links\")\n\nconst maxSymlinkLimit = 255\n\ntype onSymlinkFunc func(string, string) error\n\n// rootPath joins a path with a root, evaluating and bounding any symlink to\n// the root directory. This is a slightly modified version of SecureJoin from\n// github.com/cyphar/filepath-securejoin, with a callback which we call after\n// each symlink resolution.\nfunc rootPath(root, unsafePath string, followTrailing bool, cb onSymlinkFunc) (string, error) {\n\tif unsafePath == \"\" {\n\t\treturn root, nil\n\t}\n\n\tunsafePath = filepath.FromSlash(unsafePath)\n\tvar (\n\t\tcurrentPath string\n\t\tlinksWalked int","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/dagger/dagger/blob/82ba2681dbe30d3547a1dc50ea495900ab5b6047/engine/contenthash/path.go#L1-L36","documentation":"errTooManyLinks is a sentinel error thrown by the contenthash path resolver (rootPath and the checksum walker) when resolving a path encounters more than maxSymlinkLimit (255) symbolic links. The limit bounds symlink traversal so deeply or cyclically linked trees cannot cause infinite recursion or resource exhaustion. If you see it, the path being checksummed or resolved contains a symlink chain (typically a cycle like a -> b -> a, or a chain) longer than 255 hops.","triggerScenarios":"Calling rootPath (used by checksum, stat, include/exclude walking) on a path whose symlink chain exceeds 255 links — most commonly a symlink loop (a/b/c pointing back to an ancestor) created inside a container or mounted directory; also legitimately deep symlink chains (256+) in generated trees.","commonSituations":"A Dockerfile or script accidentally creates a self-referential symlink (e.g. ln -s . loop); a symlinked cache dir pointing back into itself after a restore; CI tooling symlink-spam in node_modules or vendored dirs; bind-mounting a directory into itself.","solutions":["Inspect the path named in your command with `ls -la` and `find -L <path> -maxdepth 300` to locate the symlink cycle or over-long chain.","Remove or rewrite the offending symlink so it no longer points to an ancestor of itself (break the loop).","Rebuild the affected directory without the loop (re-clone, restore from a clean cache, or regenerate the tree).","If a genuinely deep (>255) symlink chain is required, restructure it — flatten the chain or copy the target instead of chaining links, since the 255 limit is fixed."],"exampleFix":"// inside the container, a link pointing back at its ancestor\n// before\nln -s / /work/root-link   // /work/root-link/... can loop forever\n// after\nrm /work/root-link\nln -s /shared/data /work/data-link","handlingStrategy":"validation","validationCode":"import { execSync } from 'node:child_process'\nfunction hasSymlinkLoop(root) {\n  try {\n    // find -L reports 'too many levels of symbolic links' on cycles\n    execSync(`find -L ${JSON.stringify(root)} -maxdepth 300 -type f -quit`, { stdio: 'ignore' })\n    return false\n  } catch (e) {\n    return /Too many levels of symbolic links/i.test(e.stderr?.toString() ?? '')\n  }\n}\nif (hasSymlinkLoop('/work')) throw new Error('symlink loop under /work; fix before checksum')","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never create symlinks that point to an ancestor of themselves (e.g. ln -s / inside the tree)","Scan build inputs for symlink cycles before submitting operations (find -L or equivalent)","Restore caches/vendored dirs from clean sources rather than re-linking in place","Keep symlink chains short; copy targets instead of chaining links when depth could exceed 255"],"tags":["symlink","filesystem","contenthash","path-resolution"],"backgroundTag":"symlink-loop-detected","analyzedSha":"82ba2681dbe30d3547a1dc50ea495900ab5b6047","analyzedAt":"2026-09-05T07:21:37.930Z","contentChangedAt":"2026-09-05T07:21:37.930Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}