{"record":{"id":"aac2d3a698120912","repo":"vercel/turborepo","slug":"may-not-specify-workspace-name-in-non-root-turbo-j","errorCode":null,"errorMessage":"May not specify workspace name in non-root turbo.json","messagePattern":"May not specify workspace name in non-root turbo\\.json","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/eslint-plugin-turbo/lib/utils/calculate-inputs.ts","lineNumber":363,"sourceCode":"              taskDefinition\n            );\n          }\n        }\n      );\n    }\n\n    for (const projectWorkspace of this.projectWorkspaces) {\n      if (!projectWorkspace.turboConfig) {\n        continue;\n      }\n\n      forEachTaskDef(\n        projectWorkspace.turboConfig,\n        ([taskName, taskDefinition]) => {\n          const { workspaceName: erroneousWorkspaceName, scriptName } =\n            getTaskAddress(taskName);\n          if (erroneousWorkspaceName) {\n            throw new Error(\n              \"May not specify workspace name in non-root turbo.json\"\n            );\n          }\n\n          const workspaceName = projectWorkspace.workspaceName;\n          workspaceTasks[workspaceName] =\n            workspaceName in workspaceTasks\n              ? workspaceTasks[workspaceName]\n              : {};\n          workspaceTasks[workspaceName][scriptName] = processTask(\n            projectWorkspace.workspacePath,\n            taskDefinition\n          );\n        }\n      );\n    }\n\n    return {","sourceCodeStart":345,"sourceCodeEnd":381,"githubUrl":"https://github.com/vercel/turborepo/blob/9f94a7d215b3881942527dd526afa3fc650869d5/packages/eslint-plugin-turbo/lib/utils/calculate-inputs.ts#L345-L381","documentation":"eslint-plugin-turbo iterates every workspace's turbo.json and throws when a non-root (workspace-level) turbo.json defines tasks using the `workspace#task` form. Only the root turbo.json may address other workspaces; workspace-level task keys are implicitly scoped to that workspace, so a workspace prefix is erroneous.","triggerScenarios":"A workspace-level turbo.json (e.g. apps/web/turbo.json) containing a key like `\"packages/ui#build\"` or `\"apps/web#test\"` in its tasks/pipeline object. The throw happens while the ESLint rule processes that workspace's turboConfig.","commonSituations":"Copying the root turbo.json into a workspace as a starting point and forgetting to strip prefixes; assuming workspace configs need self-referencing `my-workspace#build` keys.","solutions":["In the workspace-level turbo.json, drop the `workspace#` prefix — keys there are implicitly local (`\"build\"` instead of `\"apps/web#build\"`)","If the config genuinely targets another workspace's task, move it into the root turbo.json, which is the only place workspace-qualified keys are allowed","Re-run ESLint to confirm the plugin resolves the config"],"exampleFix":"// apps/web/turbo.json (before)\n\"tasks\": { \"apps/web#build\": { \"outputs\": [\".next/**\"] } }\n// after\n\"tasks\": { \"build\": { \"outputs\": [\".next/**\"] } }","handlingStrategy":"validation","validationCode":"import fs from 'node:fs';\n\nfunction workspaceConfigUsesScopedKeys(workspaceTurboJsonPath: string): boolean {\n  const cfg = JSON.parse(fs.readFileSync(workspaceTurboJsonPath, 'utf8'));\n  const tasks = cfg.tasks ?? cfg.pipeline ?? {};\n  return Object.keys(tasks).some((k) => k.includes('#')); // illegal outside root turbo.json\n}","typeGuard":"function isWorkspaceScopedKey(key: string): boolean {\n  return key.includes('#');\n}","tryCatchPattern":null,"preventionTips":["Keep workspace-qualified `workspace#task` keys only in the root turbo.json","When copying root config into a workspace, strip the prefixes first","Document the convention in the repo: workspace turbo.json keys are implicitly local"],"tags":["eslint-plugin-turbo","turbo-json","workspace","config","linting"],"backgroundTag":"workspace-config-conflict","analyzedSha":"9f94a7d215b3881942527dd526afa3fc650869d5","analyzedAt":"2026-08-16T19:47:29.531Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}