angular/angular-cli · error · SchematicsException

outputPath for ${projectName} ${target} target is not a stri

Error message

outputPath for ${projectName} ${target} target is not a string.

What it means

The SSR schematic found `options` on the build target but its `outputPath` is not a plain string — the schematic only supports string output paths when computing legacy browser/server dist directories. It throws to avoid deriving wrong paths from an object-shaped outputPath.

Source

Thrown at packages/schematics/angular/ssr/index.ts:65

const DEFAULT_MEDIA_DIR = 'media';
const DEFAULT_SERVER_DIR = 'server';

async function getLegacyOutputPaths(
  host: Tree,
  projectName: string,
  target: 'server' | 'build',
): Promise<string> {
  // Generate new output paths
  const workspace = await readWorkspace(host);
  const project = workspace.projects.get(projectName);
  const architectTarget = project?.targets.get(target);
  if (!architectTarget?.options) {
    throw new SchematicsException(`Cannot find 'options' for ${projectName} ${target} target.`);
  }

  const { outputPath } = architectTarget.options;
  if (typeof outputPath !== 'string') {
    throw new SchematicsException(
      `outputPath for ${projectName} ${target} target is not a string.`,
    );
  }

  return outputPath;
}

async function getApplicationBuilderOutputPaths(
  host: Tree,
  projectName: string,
): Promise<{ browser: string; server: string; base: string }> {
  // Generate new output paths
  const target = 'build';
  const workspace = await readWorkspace(host);
  const project = workspace.projects.get(projectName);
  const architectTarget = project?.targets.get(target);

  if (!architectTarget?.options) {

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Change `outputPath` in the target's `options` to a plain string, e.g. "outputPath": "dist/my-app".
  2. If the project uses the @angular-devkit/build-angular:application builder, ensure the builder type is set correctly so the schematic takes the application-builder path instead.
  3. Migrate the project to the application builder (`ng update` or manually switch builder to `@angular-devkit/build-angular:application`).

Example fix

// before (angular.json, legacy project)
"outputPath": { "base": "dist/my-app" }
// after
"outputPath": "dist/my-app"
Defensive patterns

Strategy: validation

Validate before calling

const opts = workspace.projects.get(projectName)?.targets.get('build')?.options;
if (typeof opts?.outputPath !== 'string') {
  console.warn('Legacy build target must use a string outputPath before adding SSR.');
}

Type guard

function isStringOutputPath(v: unknown): v is string {
  return typeof v === 'string' && v.length > 0;
}

Try / catch

try {
  await ngAddSsr(projectName);
} catch (e) {
  if (String(e?.message).includes('outputPath') && String(e?.message).includes('is not a string')) {
    console.error('Set outputPath to a plain string in angular.json build target options.');
  }
  throw e;
}

Prevention

When it happens

Trigger: Running the ssr schematic against a project whose build target sets `outputPath` as an object like `{"base":"dist/app","browser":"..."}` (the application-builder form) while the project is detected as using the legacy builder path, or when outputPath is missing/another non-string type.

Common situations: Mixed workspace after Angular 17 migration where some targets use the new application builder; hand-copied outputPath config from another project; typos making outputPath an array or object in a legacy project.

Related errors


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