angular/angular-cli · error · Error

Terser failed for unknown reason.

Error message

Terser failed for unknown reason.

What it means

optimizeWithTerser calls the Terser API (via the worker pool) and expects result.code to be a string. When Terser returns a non-string code — typically because minification failed and it returned an error object/undefined instead — this error is thrown as a fallback because Terser did not surface a specific message. It means the Terser minification step failed without a diagnosable reason.

Source

Thrown at packages/angular_devkit/build_angular/src/tools/webpack/plugins/javascript-optimizer-worker.ts:229

      // esbuild in the first pass is used to minify function names
      keep_fnames: true,
      format: {
        // ASCII output is enabled here as well to prevent terser from converting back to UTF-8
        ascii_only: true,
        wrap_func_args: false,
      },
      sourceMap:
        sourcemaps &&
        ({
          asObject: true,
          // typings don't include asObject option
          // eslint-disable-next-line @typescript-eslint/no-explicit-any
        } as any),
    },
  );

  if (typeof result.code !== 'string') {
    throw new Error('Terser failed for unknown reason.');
  }

  return { code: result.code, map: result.map as object };
}

/**
 * Determines if an unknown value is an esbuild BuildFailure error object thrown by esbuild.
 * @param value A potential esbuild BuildFailure error object.
 * @returns `true` if the object is determined to be a BuildFailure object; otherwise, `false`.
 */
function isEsBuildFailure(value: unknown): value is BuildFailure {
  return !!value && typeof value === 'object' && 'errors' in value && 'warnings' in value;
}

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Set optimization to false temporarily (angular.json: configurations.production.optimization=false) to confirm Terser is the failing step, then narrow down the offending chunk
  2. Check the bundle for syntax Terser cannot handle and transpile it earlier (adjust target/compilerOptions.target in tsconfig to a lower ES level)
  3. Pin/align the terser version with what @angular-devkit/build-angular expects (npm ls terser) and reinstall to fix hoisting mismatches
  4. Upgrade @angular-devkit/build-angular / Angular CLI to the latest patch to pick up Terser fixes

Example fix

// before (tsconfig.json)
{"compilerOptions": {"target": "ESNext"}}
// after
{"compilerOptions": {"target": "ES2020"}}
Defensive patterns

Strategy: try-catch

Validate before calling

if (typeof input !== 'string' || input.length === 0) {
  throw new Error('invalid input passed to terser optimizer');
}

Type guard

function isTerserResult(r: unknown): r is { code: string; map?: object } {
  return typeof r === 'object' && r !== null && typeof (r as any).code === 'string';
}

Try / catch

try {
  const out = await optimizeWithTerser(/* ... */);
} catch (err) {
  if (err.message === 'Terser failed for unknown reason.') {
    logger.warn(`terser failed for ${file}; keeping unminified output`);
    return { code: originalCode, map: undefined };
  }
  throw err;
}

Prevention

When it happens

Trigger: Running the JavaScriptOptimizerWorker's optimizeWithTerser on a file whose Terser invocation returns { code: undefined } — e.g. invalid or exotic ES syntax Terser cannot parse, or a Terser internal error swallowed by the worker.

Common situations: Bundling code with syntax unsupported by the configured Terser/ECMA target; oversized or malformed generated bundles; incompatibility between the terser version resolved and the one expected by build-angular after dependency drift.

Related errors


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