{"record":{"id":"1d3a0dc44d1cf73a","repo":"kopia/kopia","slug":"cannot-resolve-q","errorCode":null,"errorMessage":"cannot resolve '%q'","messagePattern":"cannot resolve '%q'","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"fs/ignorefs/ignorefs.go","lineNumber":299,"sourceCode":"\tfor range maxSymlinkFollow {\n\t\ttarget, err := entry.Resolve(ctx)\n\t\tif err != nil {\n\t\t\tlink, _ := entry.Readlink(ctx)\n\t\t\treturn nil, errors.Wrapf(err, \"when resolving symlink %s of type %T, which points to %s\", entry.Name(), entry, link)\n\t\t}\n\n\t\tswitch t := target.(type) {\n\t\tcase fs.File:\n\t\t\treturn t, nil\n\t\tcase fs.Symlink:\n\t\t\tentry = t\n\t\t\tcontinue\n\t\tdefault:\n\t\t\treturn nil, errors.Wrapf(errSymlinkNotAFile, \"%s does not eventually link to a file\", entry.Name())\n\t\t}\n\t}\n\n\treturn nil, errors.Wrapf(errTooManySymlinks, \"cannot resolve '%q'\", entry.Name())\n}\n\nfunc (d *ignoreDirectory) buildContext(ctx context.Context) (*ignoreContext, error) {\n\teffectiveDotIgnoreFiles := d.parentContext.dotIgnoreFiles\n\n\tpol := d.policyTree.DefinedPolicy()\n\tif pol != nil {\n\t\teffectiveDotIgnoreFiles = pol.FilesPolicy.DotIgnoreFiles\n\t}\n\n\tvar dotIgnoreFiles []fs.File\n\n\tfor _, dotfile := range effectiveDotIgnoreFiles {\n\t\tif e, err := d.Directory.Child(ctx, dotfile); err == nil {\n\t\t\tswitch entry := e.(type) {\n\t\t\tcase fs.File:\n\t\t\t\tdotIgnoreFiles = append(dotIgnoreFiles, entry)\n","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/kopia/kopia/blob/82495e54b584c1ef6073c9e1be048f57f8aef078/fs/ignorefs/ignorefs.go#L281-L317","documentation":"resolveSymlink follows symlinks a bounded number of times; if the chain still has not resolved to a file after that many hops, it wraps errTooManySymlinks with \"cannot resolve '%q'\". This guards against symlink cycles and pathologically deep chains during ignore-rule processing.","triggerScenarios":"A symlink loop (a -> b -> a) or a chain longer than the resolver's iteration limit is encountered while buildContext walks the tree.","commonSituations":"Accidental self-referencing links (ln -s . loop), circular links created by misconfigured deployment tooling, or extremely deep symlink chains in package-manager directories.","solutions":["Find and break the symlink cycle: `find -L . -type l` or `namei -l <path>` to locate the loop","Remove or repoint the cyclic symlink","Exclude the problematic directory from the scan via ignore rules"],"exampleFix":"// before\nln -s . parent-link   // creates infinite loop\n// after\nrm parent-link        // remove the cyclic symlink or link to a bounded target","handlingStrategy":"validation","validationCode":"if tgt, err := filepath.EvalSymlinks(path); err != nil { return fmt.Errorf(\"symlink chain unresolved for %s: %w\", path, err) }","typeGuard":"func hasSymlinkLoop(root string) error { return filepath.Walk(root, func(p string, fi os.FileInfo, err error) error { if err != nil { return err }; if fi.Mode()&os.ModeSymlink != 0 { _, e := filepath.EvalSymlinks(p); return e } ; return nil }) }","tryCatchPattern":"if err != nil {\n    log.Warnf(\"symlink cycle at %s, excluding from scan\", path)\n    return filepath.SkipDir\n}","preventionTips":["Never create symlinks that point to ancestor directories (ln -s . ...)","Run `find -L . -type l` in CI to detect loops before snapshotting","Keep symlink chain depth shallow (1-2 hops)"],"tags":["symlink","infinite-loop","filesystem"],"backgroundTag":"symlink-loop-detected","analyzedSha":"82495e54b584c1ef6073c9e1be048f57f8aef078","analyzedAt":"2026-09-07T20:35:21.689Z","contentChangedAt":"2026-09-07T20:35:21.689Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}