vercel/turborepo · error · Error

May not specify workspace name in non-root turbo.json

Error message

May not specify workspace name in non-root turbo.json

What it means

eslint-plugin-turbo walks every workspace-level turbo.json and registers each task under that workspace. The "workspace#task" key syntax is only valid in the root turbo.json. This Error is thrown when a non-root turbo.json uses a workspace-qualified task name, because the plugin would store the task under the wrong workspace.

Solutions

  1. Open the workspace-level turbo.json named in the error and remove the "workspace#" prefix from every task key
  2. If you need a workspace-specific override of another workspace's task, put it in the root turbo.json where qualified names are allowed
  3. Re-run ESLint to confirm the plugin accepts the file

Example fix

// before: packages/web/turbo.json
{ "extends": ["//"], "tasks": { "web#build": { "outputs": ["dist/**"] } } }
// after: packages/web/turbo.json
{ "extends": ["//"], "tasks": { "build": { "outputs": ["dist/**"] } } }
Defensive patterns

Strategy: validation

Validate before calling

// ensure workspace-level turbo.json files use unqualified task names
import fs from "node:fs";
import path from "node:path";

for (const ws of workspaceDirs) {
  const p = path.join(ws, "turbo.json");
  if (!fs.existsSync(p)) continue;
  const tasks = JSON.parse(fs.readFileSync(p, "utf8")).tasks ?? {};
  const qualified = Object.keys(tasks).filter((k) => k.includes("#"));
  if (qualified.length > 0) {
    throw new Error(`${p}: remove workspace qualifiers from ${qualified}`);
  }
}

Type guard

function isAllowedInWorkspaceConfig(key: string): boolean {
  return !key.includes("#");
}

Prevention

When it happens

Trigger: A file like packages/web/turbo.json contains a key such as "web#build". The plugin iterates projectWorkspaces, calls getTaskAddress on the key, sees a non-null workspaceName inside a workspace-level config, and throws.

Common situations: Copying a root turbo.json into a package without stripping the workspace prefixes. Following an example that mixes root and workspace syntax. Applying a codemod that prefixes all task keys with the package name.

Related errors


AI-assisted analysis of vercel/turborepo@f9245100cf (2026-08-17). Data as JSON: /api/errors/aac2d3a698120912. Report an issue: GitHub.

Appendix: source

Thrown at packages/eslint-plugin-turbo/lib/utils/calculate-inputs.ts:363

              taskDefinition
            );
          }
        }
      );
    }

    for (const projectWorkspace of this.projectWorkspaces) {
      if (!projectWorkspace.turboConfig) {
        continue;
      }

      forEachTaskDef(
        projectWorkspace.turboConfig,
        ([taskName, taskDefinition]) => {
          const { workspaceName: erroneousWorkspaceName, scriptName } =
            getTaskAddress(taskName);
          if (erroneousWorkspaceName) {
            throw new Error(
              "May not specify workspace name in non-root turbo.json"
            );
          }

          const workspaceName = projectWorkspace.workspaceName;
          workspaceTasks[workspaceName] =
            workspaceName in workspaceTasks
              ? workspaceTasks[workspaceName]
              : {};
          workspaceTasks[workspaceName][scriptName] = processTask(
            projectWorkspace.workspacePath,
            taskDefinition
          );
        }
      );
    }

    return {

View on GitHub (pinned to f9245100cf)