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

  1. Delete one config file in the affected workspace directory listed in the message
  2. Search the whole repo for duplicates: find . -name 'turbo.json*' -not -path '*/node_modules/*' and ensure each directory has exactly one
  3. If migrating to JSONC repo-wide, script the rename and git rm the old files in one commit
  4. 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

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


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 extends

View on GitHub (pinned to f9245100cf)