vercel/turborepo · error
Found both turbo.json and turbo.jsonc in the same directory
Error message
Found both turbo.json and turbo.jsonc in the same directory: ${dirPath}
Please use either turbo.json or turbo.jsonc, but not both. What it means
A second guard in get-turbo-configs.ts, on the per-workspace resolution path: after resolveTurboConfigPath returns a configPath for a workspace, the loader detects that the workspace directory holds both turbo.json and turbo.jsonc and throws the same 'use one, not both' error. The first guard (line 196) covers the multi-config discovery loop; this one covers the single-workspace resolve path.
Solutions
- Delete one config file in the affected workspace directory listed in the message
- Search the whole repo for duplicates: find . -name 'turbo.json*' -not -path '*/node_modules/*' and ensure each directory has exactly one
- If migrating to JSONC repo-wide, script the rename and git rm the old files in one commit
- Add a CI check that fails when a directory contains both filenames
Example fix
# before packages/app/turbo.json packages/app/turbo.jsonc # Error: Found both turbo.json and turbo.jsonc in the same directory: /repo/packages/app # after rm packages/app/turbo.json # single turbo.jsonc remains
Defensive patterns
Strategy: validation
Validate before calling
import { existsSync, readdirSync } from "node:fs";
function findDuplicateConfigDirs(root: string): string[] {
return readdirSync(root, { recursive: true, withFileTypes: true })
.filter((d) => d.isDirectory() && d.name !== "node_modules")
.map((d) => join(d.path, d.name))
.filter((dir) => existsSync(join(dir, "turbo.json")) && existsSync(join(dir, "turbo.jsonc")));
} Prevention
- After any workspace scaffold/copy step, assert each directory holds exactly one turbo config
- Treat config duplication as a merge artifact and check 'git ls-files | grep turbo.json' in review
- Add a preflight check in CI before running turbo commands
When it happens
Trigger: Calling the workspace-config resolution API for a workspacePath whose directory physically contains turbo.json and turbo.jsonc at the same time; resolveTurboConfigPath surfaces the ambiguity and the error is re-thrown after being logged.
Common situations: Same as the sibling error: converting a repo to turbo.jsonc without deleting turbo.json, sync tools or generators that add turbo.json into packages already configured with turbo.jsonc, or platform case-insensitivity making what looks like one file into two.
Related errors
- Found both turbo.json and turbo.jsonc in the same directory
- May not specify workspace name in non-root turbo.json
- no caches are enabled
- [33m"turbo-ignore" is deprecated. Use "turbo query…
- --affected could not determine changed files. All tasks…
AI-assisted analysis of vercel/turborepo@f9245100cf (2026-08-17).
Data as JSON: /api/errors/0ab9cb6c6ba7a7b7.
Report an issue: GitHub.
Appendix: source
Thrown at packages/turbo-utils/src/get-turbo-configs.ts:288
const workspaceName = packageJsonContent.name;
const workspacePath = path.dirname(configPath);
const isWorkspaceRoot = workspacePath === turboRoot;
// Try and get turbo.json or turbo.jsonc
const {
configPath: turboConfigPath,
configExists,
error
} = resolveTurboConfigPath(workspacePath);
let rawTurboJson = null;
let turboConfig: SchemaV1 | undefined;
try {
if (error) {
logger.error(error);
throw new Error(error);
}
if (configExists && turboConfigPath) {
rawTurboJson = fs.readFileSync(turboConfigPath, "utf8");
}
if (rawTurboJson) {
turboConfig = JSON5.parse(rawTurboJson);
if (turboConfig) {
// basic config validation
if (isWorkspaceRoot) {
// invalid - root config with extends
if ("extends" in turboConfig) {
continue;
}
} else if (!("extends" in turboConfig)) {
// invalid - workspace config with no extendsView on GitHub (pinned to f9245100cf)