affaan-m/ECC · error · Error
Refusing to ${action}: missing destination path.
Error message
Refusing to ${action}: missing destination path. What it means
Thrown by assertWithinTrustedRoot(target, root, action) in scripts/lib/path-safety.js when `target` is falsy or not a string. This is a fail-closed path-containment guard: before any write/delete/read operation replayed from install state, the destination path must be a concrete string so it can be canonicalized and confined to the trusted root (GHSA-hfpv-w6mp-5g95).
Source
Thrown at scripts/lib/path-safety.js:87
function isWithinRoot(target, root) {
if (!root) {
return false;
}
try {
return resolveContainment(target, root).contained;
} catch {
return false;
}
}
/**
* Fail-closed guard: throw unless `target` is contained within `root`.
* Returns the canonicalized target path on success.
*/
function assertWithinTrustedRoot(target, root, action = 'write') {
if (!target || typeof target !== 'string') {
throw new Error(`Refusing to ${action}: missing destination path.`);
}
if (!root) {
throw new Error(`Refusing to ${action} '${target}': no trusted install root resolved.`);
}
let containment;
try {
containment = resolveContainment(target, root);
} catch {
containment = null;
}
if (!containment || !containment.contained) {
throw new Error(`Refusing to ${action} outside the install root: '${target}' is not within '${root}'.`);
}
return containment.realTarget;
}
module.exports = {View on GitHub (pinned to 01e15490f0)
Solutions
- Ensure the operation record always carries a destinationPath string before replay.
- Skip state entries whose path is missing rather than passing them to the guard.
- Validate the install-state file shape at load time and drop malformed entries.
- When building the target yourself, always call path.resolve on a real string.
Example fix
// before const safe = assertWithinTrustedRoot(op.dest, trustedRoot, 'write'); // op.dest undefined // after if (!op || typeof op.dest !== 'string' || op.dest.length === 0) continue; const safe = assertWithinTrustedRoot(op.dest, trustedRoot, 'write');
Defensive patterns
Strategy: validation
Validate before calling
if (!target || typeof target !== 'string') {
throw new Error('destination path required for ' + action);
}
assertWithinTrustedRoot(target, root, action); Type guard
function isNonEmptyPath(value) {
return typeof value === 'string' && value.length > 0;
} Prevention
- Validate install-state entries at load time and drop ones missing destinationPath.
- Always resolve real string paths before recording them in state.
- Skip malformed operations rather than passing them to the guard.
When it happens
Trigger: Calling assertWithinTrustedRoot(undefined, root, 'write'), assertWithinTrustedRoot('', root), assertWithinTrustedRoot(null, root), or passing a non-string destination read from a malformed install-state file.
Common situations: An install-state JSON entry missing a destinationPath key; a repair/uninstall loop replaying a recorded operation whose path field was never persisted; a refactor that passes a path object instead of a string; a symlink target that resolved to empty.
Related errors
- Refusing to ${action} '${target}': no trusted install root r
- Refusing to ${action} outside the install root: '${target}'
- TypeScript compiler not found. Install root dev dependencies
- ${source} is missing the expected catalog marker
- Invalid ${flag}: expected a single cache path segment
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/2e84ef5bc4f5a6cd.
Report an issue: GitHub.