no-cycle finds 0 cycles in next.js (and other lies caches tell you) The article describes a bug in a cycle-detection algorithm used in an ESLint plugin for Next.js, where a depth limit in the DFS search caused files to be incorrectly cached as "acyclic" when the search was truncated before finding a cycle. This caching bug cascaded across thousands of files, causing the tool to report zero cycles in a large codebase (14,556 files) while smaller scopes and a different tool (oxlint) correctly found 17 cycles. The fix involves tracking whether the DFS was truncated by the depth limit and only caching files as acyclic when the search fully completes without finding a cycle. We benchmark import-next/no-cycle against eslint-plugin-import/no-cycle and oxlint's native Rust port on next.js 131K stars, 14,556 source files . The two ESLint plugins agreed: 0 cycles found. oxlint disagreed: 17 cycles found. We trusted the consensus. Then we tested our own rule on a 33-file subset of the same repo packages/next/src/client/components/router-reducer/ . It found 5+ cycles immediately. Same rule. Same config. Same files. Different scope. Different answers. The bug was 60 lines deep in the cache layer — and it explains why the wider scope returned silence. Every cycle-detection algorithm has the same shape: Step 4 is where caching pays off. With N files and average graph depth D, naive cycle detection is O N²·D . With a "known acyclic" cache, repeat visits are O 1 . On real codebases the cache hit rate is 70%+ — without it the rule gets too slow to run in CI. The shape of the cache: interface FileSystemCache { // ... nonCyclicFiles: Set