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
- Open the workspace-level turbo.json named in the error and remove the "workspace#" prefix from every task key
- If you need a workspace-specific override of another workspace's task, put it in the root turbo.json where qualified names are allowed
- 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
- Keep workspace-qualified task keys only in the root turbo.json
- Use the extends: ["//"] convention in workspace turbo.json files
- Review copied root configs before placing them in packages
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
- Invalid task name found in turbo.json.
- Found both turbo.json and turbo.jsonc in the same directory
- Found both turbo.json and turbo.jsonc in the same directory
- New workspace root detected - unexpected 'workspaces' field…
- Directory path contains potentially unsafe characters
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)