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
- Ensure the from path is absolute: call resolve('/') or join(NormalizedRoot, path) before passing it to relative()
- Normalize the input with normalize(path) so separators and root are correct
- 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
- Always normalize external input with normalize() before path math
- Never pass PathFragment values where a full Path is required
- Check isAbsolute() on both arguments before calling relative()
- Convert OS paths (e.g. Windows) to normalized virtual-fs paths first
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
- Path is a directory.
- Path is a file.
- Path ${JSON.stringify(path)} cannot be made a fragment.
- File does not exist.
- File already exist.
AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30).
Data as JSON: /api/errors/8006b2b69e08c95d.
Report an issue: GitHub.