angular/angular-cli · error · Error

Project "${projectName}" is missing a required property "roo

Error message

Project "${projectName}" is missing a required property "root".

What it means

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.

Source

Thrown at packages/angular_devkit/core/src/workspace/json/reader.ts:188

function parseProject(
  projectName: string,
  projectNode: Node,
  context: ParserContext,
): ProjectDefinition {
  const jsonMetadata = context.metadata;
  let targets;
  let hasTargets = false;
  let extensions: Record<string, JsonValue> | undefined;
  let properties: Record<'root' | 'sourceRoot' | 'prefix', string> | undefined;
  if (!context.trackChanges) {
    // If not tracking changes, the parser will store the values directly in standard objects
    extensions = Object.create(null);
    properties = Object.create(null);
  }

  const projectNodeValue = getNodeValue(projectNode);
  if (!('root' in projectNodeValue)) {
    throw new Error(`Project "${projectName}" is missing a required property "root".`);
  }

  for (const [name, value] of Object.entries<JsonValue>(projectNodeValue)) {
    switch (name) {
      case 'targets':
      case 'architect': {
        const nodes = findNodeAtLocation(projectNode, [name]);
        if (!isJsonObject(value) || !nodes) {
          context.error(`Invalid "${name}" field found; expected an object.`, value);
          break;
        }
        hasTargets = true;
        targets = parseTargetsObject(projectName, nodes, context);
        jsonMetadata.hasLegacyTargetsName = name === 'architect';
        break;
      }
      case 'prefix':
      case 'root':

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Add a `root` property to the named project in angular.json (use "" for a project rooted at the workspace root)
  2. Restore the missing line from git history (`git show HEAD:angular.json`)
  3. Regenerate the project entry with `ng generate` tooling instead of hand-writing it

Example fix

// before (angular.json)
"projects": { "my-app": { "prefix": "app", "architect": {} } }
// after
"projects": { "my-app": { "root": "projects/my-app", "prefix": "app", "architect": {} } }
Defensive patterns

Strategy: validation

Validate before calling

const ws = JSON.parse(text);
for (const [name, proj] of Object.entries(ws.projects ?? {})) {
  if (typeof proj?.root !== 'string') throw new Error(`Project "${name}" is missing required "root".`);
}

Type guard

function hasProjectRoot(p) {
  return typeof p === 'object' && p !== null && typeof p.root === 'string';
}

Try / catch

try {
  const ws = await parseWorkspace(host, logger, text, options);
} catch (err) {
  if (err.message.includes('missing a required property "root"')) {
    throw new Error(`Fix angular.json: ${err.message}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: parseProject (via parseProjectsObject) encounters a project object in the workspace that lacks the `root` property — e.g. `{ "projects": { "my-app": { "architect": {} } } }` with no `"root": ""`.

Common situations: 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.

Related errors


AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30). Data as JSON: /api/errors/249e571ae2e4fdd1. Report an issue: GitHub.