{"record":{"id":"249e571ae2e4fdd1","repo":"angular/angular-cli","slug":"project-projectname-is-missing-a-required-pro","errorCode":null,"errorMessage":"Project \"${projectName}\" is missing a required property \"root\".","messagePattern":"Project \"(.+?)\" is missing a required property \"root\"\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/angular_devkit/core/src/workspace/json/reader.ts","lineNumber":188,"sourceCode":"function parseProject(\n  projectName: string,\n  projectNode: Node,\n  context: ParserContext,\n): ProjectDefinition {\n  const jsonMetadata = context.metadata;\n  let targets;\n  let hasTargets = false;\n  let extensions: Record<string, JsonValue> | undefined;\n  let properties: Record<'root' | 'sourceRoot' | 'prefix', string> | undefined;\n  if (!context.trackChanges) {\n    // If not tracking changes, the parser will store the values directly in standard objects\n    extensions = Object.create(null);\n    properties = Object.create(null);\n  }\n\n  const projectNodeValue = getNodeValue(projectNode);\n  if (!('root' in projectNodeValue)) {\n    throw new Error(`Project \"${projectName}\" is missing a required property \"root\".`);\n  }\n\n  for (const [name, value] of Object.entries<JsonValue>(projectNodeValue)) {\n    switch (name) {\n      case 'targets':\n      case 'architect': {\n        const nodes = findNodeAtLocation(projectNode, [name]);\n        if (!isJsonObject(value) || !nodes) {\n          context.error(`Invalid \"${name}\" field found; expected an object.`, value);\n          break;\n        }\n        hasTargets = true;\n        targets = parseTargetsObject(projectName, nodes, context);\n        jsonMetadata.hasLegacyTargetsName = name === 'architect';\n        break;\n      }\n      case 'prefix':\n      case 'root':","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/angular/angular-cli/blob/bb72145f9ab45aee29f523236b3a25cd0813a841/packages/angular_devkit/core/src/workspace/json/reader.ts#L170-L206","documentation":"parseProject requires every project entry in the workspace to have a `root` property defining its source directory. If the project's object has no `root` key, the reader throws. `root` is the one mandatory field of a project definition in angular.json; everything else (targets, prefixes, etc.) is optional.","triggerScenarios":"parseProject (via parseProjectsObject) encounters a project object in the workspace that lacks the `root` property — e.g. `{ \"projects\": { \"my-app\": { \"architect\": {} } } }` with no `\"root\": \"\"`.","commonSituations":"Manually copying a project entry into angular.json and dropping the root field; older 1.x-era or third-party tooling writing minimal project entries; merge conflicts where the root line was deleted.","solutions":["Add a `root` property to the named project in angular.json (use \"\" for a project rooted at the workspace root)","Restore the missing line from git history (`git show HEAD:angular.json`)","Regenerate the project entry with `ng generate` tooling instead of hand-writing it"],"exampleFix":"// before (angular.json)\n\"projects\": { \"my-app\": { \"prefix\": \"app\", \"architect\": {} } }\n// after\n\"projects\": { \"my-app\": { \"root\": \"projects/my-app\", \"prefix\": \"app\", \"architect\": {} } }","handlingStrategy":"validation","validationCode":"const ws = JSON.parse(text);\nfor (const [name, proj] of Object.entries(ws.projects ?? {})) {\n  if (typeof proj?.root !== 'string') throw new Error(`Project \"${name}\" is missing required \"root\".`);\n}","typeGuard":"function hasProjectRoot(p) {\n  return typeof p === 'object' && p !== null && typeof p.root === 'string';\n}","tryCatchPattern":"try {\n  const ws = await parseWorkspace(host, logger, text, options);\n} catch (err) {\n  if (err.message.includes('missing a required property \"root\"')) {\n    throw new Error(`Fix angular.json: ${err.message}`);\n  }\n  throw err;\n}","preventionTips":["Always include \"root\" (even \"\" for workspace-rooted projects) when defining projects","Validate angular.json against the official workspace schema in CI","Avoid hand-merging project entries; resolve merge conflicts by regenerating entries"],"tags":["json","workspace","schema-validation","angular-cli"],"backgroundTag":"missing-required-property","analyzedSha":"bb72145f9ab45aee29f523236b3a25cd0813a841","analyzedAt":"2026-08-30T02:47:34.745Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}