{"record":{"id":"e9fdbb3601928b49","repo":"vercel/turborepo","slug":"skipping-automatic-task-caching-output-generated","errorCode":null,"errorMessage":"skipping automatic task caching - output generated outside of repo root ({output})","messagePattern":"skipping automatic task caching - output generated outside of repo root \\((.+?)\\)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/turborepo-lib/src/run/task_access.rs","lineNumber":134,"sourceCode":"                            format!(\n                                \"skipping automatic task caching - file accessed outside of repo \\\n                                 root ({unescaped_str})\"\n                            ),\n                        )\n                        .emit();\n                        return false;\n                    }\n                }\n                Err(e) => {\n                    debug!(\"failed to parse path {unescaped_str}: {e}\");\n                }\n            }\n        }\n\n        for output in &self.outputs {\n            let output = output.strip_prefix('!').unwrap_or(output.as_str());\n            if is_windows_absolute_path(output) {\n                turborepo_log::warn(\n                    turborepo_log::Source::turbo(turborepo_log::Subsystem::TaskAccess),\n                    format!(\n                        \"skipping automatic task caching - output generated outside of repo root \\\n                         ({output})\"\n                    ),\n                )\n                .emit();\n                return false;\n            }\n\n            let path = AbsoluteSystemPathBuf::new(output.to_string())\n                .unwrap_or_else(|_| AbsoluteSystemPathBuf::from_unknown(repo_root, output));\n            let relation = path.relation_to_path(repo_root);\n            if relation == PathRelation::Parent || relation == PathRelation::Divergent {\n                turborepo_log::warn(\n                    turborepo_log::Source::turbo(turborepo_log::Subsystem::TaskAccess),\n                    format!(\n                        \"skipping automatic task caching - output generated outside of repo root \\","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/vercel/turborepo/blob/f9245100cf0d31d96628804ead485f6bf226e55a/crates/turborepo-lib/src/run/task_access.rs#L116-L152","documentation":"During automatic-caching validation of outputs, TaskAccess::can_cache (crates/turborepo-lib/src/run/task_access.rs:137-151) first checks each declared output (with a leading '!' inverted-glob marker stripped) using is_windows_absolute_path. A Windows-absolute output like C:\\\\build\\\\dist cannot be anchored to the repo root, so the task is skipped from automatic caching with this warning.","triggerScenarios":"A task's outputs entry is an absolute Windows path — typically produced by scripts that interpolate %SYSTEMDRIVE%-style roots, MSBuild-style output dirs, or hardcoded drive letters into turbo.json/config. The check runs per output before the repo-root relation test.","commonSituations":"turbo.json authored on Windows with a copied absolute path (C:\\\\Users\\\\me\\\\repo\\\\dist), CI matrices where a Windows runner config is reused from a local absolute path, and generators that emit absolute outputs instead of package-relative globs.","solutions":["Replace absolute paths with package-relative globs in the task's outputs: \"dist/**\" instead of C:\\\\repo\\\\package\\\\dist.","Regenerate or hand-fix any config that injects drive letters; outputs are always resolved relative to the package root.","If an output truly must live outside the package, use a symlink inside the package or move the producing step to a non-cached task.","Search the repo for drive-letter patterns ([A-Z]:\\\\\\) in turbo.json files to catch all instances."],"exampleFix":"// turbo.json — before: Windows-absolute output\n\"tasks\": { \"build\": { \"outputs\": [\"C:\\\\repo\\\\packages\\\\web\\\\dist\"] } }\n// -> skipping automatic task caching - output generated outside of repo root\n\n// after: package-relative glob\n\"tasks\": { \"build\": { \"outputs\": [\"dist/**\"] } }","handlingStrategy":"validation","validationCode":"// validate turbo.json outputs are package-relative before running\nimport turboJson from \"./turbo.json\" assert { type: \"json\" };\nconst isWindowsAbsolute = (p: string) => /^[a-zA-Z]:[\\\\\\/]/.test(p);\nfor (const [task, def] of Object.entries<any>(turboJson.tasks ?? {})) {\n  for (const out of def.outputs ?? []) {\n    if (isWindowsAbsolute(out)) {\n      throw new Error(`task \"${task}\" output \"${out}\" is Windows-absolute; use a package-relative glob`);\n    }\n  }\n}","typeGuard":"const isPackageRelativeOutput = (output: string): boolean =>\n  !/^[a-zA-Z]:[\\\\\\/]/.test(output) && !output.startsWith(\"/\") && !output.startsWith(\"..\");","tryCatchPattern":null,"preventionTips":["Author outputs as package-relative globs only (dist/**, build/*).","Add a config lint step that rejects drive-letter or rooted paths in outputs.","Never paste absolute local paths into shared turbo.json files."],"tags":["turborepo","caching","outputs","windows","absolute-path"],"backgroundTag":"absolute-path-in-task-config","analyzedSha":"f9245100cf0d31d96628804ead485f6bf226e55a","analyzedAt":"2026-08-17T10:46:15.696Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}