{"record":{"id":"fab287ce23e5114e","repo":"tailwindlabs/tailwindcss","slug":"exceeded-maximum-recursion-depth-while-resolving","errorCode":null,"errorMessage":"Exceeded maximum recursion depth while resolving `${uri}` in `${base}`)","messagePattern":"Exceeded maximum recursion depth while resolving `(.+?)` in `(.+?)`\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/tailwindcss/src/at-import.ts","lineNumber":54,"sourceCode":"      let { uri, layer, media, supports } = parsed\n\n      // Skip importing data or remote URIs\n      if (uri.startsWith('data:')) return\n      if (uri.startsWith('http://') || uri.startsWith('https://')) return\n\n      let contextNode = context({}, [])\n\n      promises.push(\n        (async () => {\n          // Since we do not have fully resolved paths in core, we can't\n          // reliably detect circular imports. Instead, we try to limit the\n          // recursion depth to a number that is too large to be reached in\n          // practice.\n          if (recurseCount > 100) {\n            throw new Error(\n              `Exceeded maximum recursion depth while resolving \\`${uri}\\` in \\`${base}\\`)`,\n            )\n          }\n\n          let loaded = await loadStylesheet(uri, base)\n          let ast = CSS.parse(loaded.content, { from: track ? loaded.path : undefined })\n          await substituteAtImports(ast, loaded.base, loadStylesheet, recurseCount + 1, track)\n\n          contextNode.nodes = buildImportNodes(\n            node,\n            [context({ base: loaded.base }, ast)],\n            layer,\n            media,\n            supports,\n          )\n        })(),\n      )\n\n      // The resolved Stylesheets already have their transitive @imports\n      // resolved, so we can skip walking them.\n      return WalkAction.ReplaceSkip(contextNode)","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/tailwindlabs/tailwindcss/blob/16e94cbf7f965c5ad697e90e940b5e178efad67c/packages/tailwindcss/src/at-import.ts#L36-L72","documentation":"Thrown by `substituteAtImports` when `recurseCount > 100`. Tailwind does not fully resolve import paths, so it cannot reliably detect true cycles; instead it caps `@import` recursion depth. Hitting the cap almost always indicates a circular import chain (A imports B imports A).","triggerScenarios":"Two stylesheets that `@import` each other, or a self-importing file; a long legitimate chain deeper than 100 (extremely rare). The guard fires before attempting to `loadStylesheet` for the current `uri`.","commonSituations":"Refactor that moved `@import` statements between files and accidentally created a cycle; generated CSS that emits imports programmatically; broken relative paths that resolve back to the parent.","solutions":["Inspect the `uri` and `base` in the message and trace the import chain back to the file that re-imports an ancestor.","Break the cycle by inlining the shared CSS into a third file both import once.","Remove redundant `@import` lines introduced during a merge or refactor."],"exampleFix":"// before\n// a.css\n@import \"b.css\";\n// b.css\n@import \"a.css\"; /* circular */\n// after\n// shared.css holds the common rules; a.css and b.css both import only shared.css","handlingStrategy":"validation","validationCode":"function detectImportCycle(entry, load, seen = new Set()) {\n  if (seen.has(entry)) throw new Error(`Circular @import involving ${entry}`);\n  seen.add(entry);\n  for (const imp of extractImports(load(entry))) detectImportCycle(imp, load, new Set(seen));\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run a dependency-graph check (e.g. madge) on CSS files to catch cycles before build.","Prefer a single shared `@import` tree over mutual imports between feature files."],"tags":["tailwind","at-import","circular","recursion"],"backgroundTag":null,"analyzedSha":"16e94cbf7f965c5ad697e90e940b5e178efad67c","analyzedAt":"2026-08-12T06:02:42.469Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}