angular/angular-cli · warning

Project property "${name}" should be a string.

Error message

Project property "${name}" should be a string.

What it means

While parsing a project definition in angular.json, the reader warns when the 'prefix', 'root', or 'sourceRoot' property is present but is not a string. The value is still copied through (cast), but behavior may be broken downstream.

Source

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

  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':
      case 'sourceRoot':
        if (typeof value !== 'string') {
          context.warn(`Project property "${name}" should be a string.`, value);
        }
        if (properties) {
          properties[name] = value as string;
        }
        break;
      default:
        if (!context.unprefixedProjectExtensions.has(name) && !/^[a-z]{1,3}-.*/.test(name)) {
          context.warn(
            `Project '${projectName}' contains extension with invalid name (${name}).`,
            name,
          );
        }
        if (extensions) {
          extensions[name] = value;
        }
        break;
    }
  }

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Set the offending property to a proper string value (e.g. "root": "projects/my-app").
  2. Remove the property if it has no meaningful value (root defaults).
  3. Fix the generator/script that produced the non-string value.

Example fix

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

Strategy: type-guard

Validate before calling

const json = require('./angular.json');
for (const [name, p] of Object.entries(json.projects ?? {})) {
  for (const key of ['prefix', 'root', 'sourceRoot']) {
    if (key in p && typeof p[key] !== 'string') {
      throw new Error(`projects.${name}.${key} must be a string, got ${typeof p[key]}: ${JSON.stringify(p[key])}`);
    }
  }
}

Type guard

function isStringProp(v) {
  return typeof v === 'string';
}

Prevention

When it happens

Trigger: parseProject handles the 'prefix'/'root'/'sourceRoot' cases and finds typeof value !== 'string' (e.g. "root": 0 or "sourceRoot": true).

Common situations: Script-generated angular.json writing numbers/nulls; hand-edits quoting mistakes; template placeholders left unexpanded (e.g. "root": null).

Related errors


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