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
- 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
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
- 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
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
- Workspace config file cannot be loaded: ${configPath}
- ${message}
- Could not find ${level} workspace.
- Invalid config found at ${workspace.filePath}. CLI should be
- Could not find a ${level} workspace. Are you in a project?
AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30).
Data as JSON: /api/errors/249e571ae2e4fdd1.
Report an issue: GitHub.