angular/angular-cli · error · PathMustBeAbsoluteException

Path ${JSON.stringify(path)} must be absolute.

Error message

Path ${JSON.stringify(path)} must be absolute.

What it means

The virtual-fs relative(from, to) function computes a path such that join(from, relative(from, to)) === to. It only makes sense for absolute normalized paths, so it throws PathMustBeAbsoluteException when the `from` argument is relative. Normalized virtual paths must start with '/' (the NormalizedRoot).

Source

Thrown at packages/angular_devkit/core/src/virtual-fs/path.ts:131

  } else {
    return p1;
  }
}

/**
 * Returns true if a path is absolute.
 */
export function isAbsolute(p: Path): boolean {
  return p.startsWith(NormalizedSep);
}

/**
 * Returns a path such that `join(from, relative(from, to)) == to`.
 * Both paths must be absolute, otherwise it does not make much sense.
 */
export function relative(from: Path, to: Path): Path {
  if (!isAbsolute(from)) {
    throw new PathMustBeAbsoluteException(from);
  }
  if (!isAbsolute(to)) {
    throw new PathMustBeAbsoluteException(to);
  }

  let p: string;

  if (from == to) {
    p = '';
  } else {
    const splitFrom = split(from);
    const splitTo = split(to);

    while (splitFrom.length > 0 && splitTo.length > 0 && splitFrom[0] == splitTo[0]) {
      splitFrom.shift();
      splitTo.shift();
    }

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Ensure the from path is absolute: call resolve('/') or join(NormalizedRoot, path) before passing it to relative()
  2. Normalize the input with normalize(path) so separators and root are correct
  3. Check with isAbsolute(path) and throw/handle your own error with a clearer message upstream

Example fix

// before
const rel = relative(path.basename(fullPath), targetPath); // from is a fragment
// after
const rel = relative(normalize(fullPath), normalize(targetPath));
Defensive patterns

Strategy: validation

Validate before calling

import { relative, isAbsolute, normalize, Path } from '@angular-devkit/core';
function safeRelative(from: string, to: string): Path {
  const f = normalize(from), t = normalize(to);
  if (!isAbsolute(f)) throw new Error(`'from' must be absolute: ${from}`);
  if (!isAbsolute(t)) throw new Error(`'to' must be absolute: ${to}`);
  return relative(f, t);
}

Type guard

import { isAbsolute, Path } from '@angular-devkit/core';
function isAbsolutePath(p: Path): p is Path {
  return typeof p === 'string' && p.startsWith('/') && isAbsolute(p);
}

Try / catch

try {
  return relative(from, to);
} catch (e) {
  if (/must be absolute/.test(e.message)) {
    return relative(normalize(resolve('/', from)), normalize(resolve('/', to)));
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling relative() with a `from` path that does not start with '/' — e.g. a fragment like 'src/app', './src', or a raw OS path like 'C:\\project' or a Windows backslash path not normalized to '/c/project'.

Common situations: Mixing PathFragment values (file names) with full Path values; passing unnormalized process.cwd() or user-supplied relative paths into virtual-fs utilities; forgetting to use normalize() or resolve() before calling relative().

Related errors


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