angular/angular-cli · error · Error

${formatDiagnostics(configResult.errors)}

Error message

${formatDiagnostics(configResult.errors)}

What it means

readTsconfig delegates parsing and validation of the TypeScript configuration file to @angular/compiler-cli's readConfiguration. If the compiler-cli reports configuration errors (parse errors, invalid options, missing extends targets), the formatted diagnostics are thrown as a single Error. This is the Angular build system's way of surfacing TypeScript config problems before compilation starts.

Source

Thrown at packages/angular_devkit/build_angular/src/utils/read-tsconfig.ts:29

/**
 * Reads and parses a given TsConfig file.
 *
 * @param tsconfigPath - An absolute or relative path from 'workspaceRoot' of the tsconfig file.
 * @param workspaceRoot - workspaceRoot root location when provided
 * it will resolve 'tsconfigPath' from this path.
 */
export async function readTsconfig(
  tsconfigPath: string,
  workspaceRoot?: string,
): Promise<ParsedConfiguration> {
  const tsConfigFullPath = workspaceRoot ? path.resolve(workspaceRoot, tsconfigPath) : tsconfigPath;

  const { formatDiagnostics, readConfiguration } = await import('@angular/compiler-cli');

  const configResult = readConfiguration(tsConfigFullPath);
  if (configResult.errors && configResult.errors.length) {
    throw new Error(formatDiagnostics(configResult.errors));
  }

  return configResult;
}

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Read the diagnostics in the error message — they name the exact file and JSON path of each config error
  2. Fix the reported tsconfig errors (syntax, missing extends target, invalid compilerOptions)
  3. Confirm the tsConfig path in angular.json resolves to an existing file relative to the workspace root
  4. Align your TypeScript version with the one supported by your @angular-devkit/build_angular version

Example fix

// before
class App { }
// after
export class App { }
Defensive patterns

Strategy: validation

Validate before calling

import { readFileSync } from 'fs';
import * as JSONC from 'jsonc-parser';
const raw = readFileSync(tsconfigPath, 'utf8');
const errors: any[] = [];
JSONC.parse(raw, errors, { allowTrailingComma: true });
if (errors.length) throw new Error(`Invalid tsconfig ${tsconfigPath}: ${errors.map(e => e.error).join(', ')}`);
// also check extends target exists:
const cfg = JSONC.parse(raw);
if (cfg.extends && !require('fs').existsSync(require('path').resolve(require('path').dirname(tsconfigPath), cfg.extends))) {
  throw new Error(`tsconfig extends target not found: ${cfg.extends}`);
}

Type guard

function isTsConfigResult(r: unknown): r is { options: ts.CompilerOptions; fileNames: string[]; errors: ts.Diagnostic[] } {
  return !!r && typeof r === 'object' && 'options' in r && 'fileNames' in r;
}

Try / catch

let config;
try {
  config = await readTsconfig(tsconfigPath);
} catch (e) {
  // message contains formatted TS diagnostics; log and surface to user
  console.error('tsconfig invalid:', (e as Error).message);
  process.exit(1);
}

Prevention

When it happens

Trigger: Calling readTsconfig with a tsconfig path whose JSON is syntactically invalid (comments/trailing commas without JSON5 support, BOM issues), references an 'extends' file that doesn't exist, or contains compilerOptions values rejected by the TypeScript version bundled with the CLI.

Common situations: Typo in angular.json tsConfig path pointing at the wrong file, tsconfig.extends pointing at a deleted base config, incompatible compilerOptions after a TypeScript upgrade (e.g. removed 'target' values), hand-edited tsconfig with a stray comma.

Related errors


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