dagger/dagger · error
too many links
Error message
too many links
What it means
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.
Source
Thrown at engine/contenthash/path.go:18
// This code mostly comes from <https://github.com/cyphar/filepath-securejoin>.
// Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved.
// Copyright (C) 2017-2024 SUSE LLC. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package contenthash
import (
"os"
"path/filepath"
"strings"
"github.com/pkg/errors"
)
var errTooManyLinks = errors.New("too many links")
const maxSymlinkLimit = 255
type onSymlinkFunc func(string, string) error
// rootPath joins a path with a root, evaluating and bounding any symlink to
// the root directory. This is a slightly modified version of SecureJoin from
// github.com/cyphar/filepath-securejoin, with a callback which we call after
// each symlink resolution.
func rootPath(root, unsafePath string, followTrailing bool, cb onSymlinkFunc) (string, error) {
if unsafePath == "" {
return root, nil
}
unsafePath = filepath.FromSlash(unsafePath)
var (
currentPath string
linksWalked intView on GitHub (pinned to 82ba2681db)
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.
Example fix
// inside the container, a link pointing back at its ancestor // before ln -s / /work/root-link // /work/root-link/... can loop forever // after rm /work/root-link ln -s /shared/data /work/data-link
Defensive patterns
Strategy: validation
Validate before calling
import { execSync } from 'node:child_process'
function hasSymlinkLoop(root) {
try {
// find -L reports 'too many levels of symbolic links' on cycles
execSync(`find -L ${JSON.stringify(root)} -maxdepth 300 -type f -quit`, { stdio: 'ignore' })
return false
} catch (e) {
return /Too many levels of symbolic links/i.test(e.stderr?.toString() ?? '')
}
}
if (hasSymlinkLoop('/work')) throw new Error('symlink loop under /work; fix before checksum') Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- failed to resolve symlinks in %s
- readlink %s: %w
- resolve nested repository path %q: %w
- workspace config directory: %w
- workspace lock directory: %w
AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05).
Data as JSON: /api/errors/a01337937f4f2c1a.
Report an issue: GitHub.