affaan-m/ECC · error
Refusing to : missing destination path.
Error message
Refusing to ${action}: missing destination path. What it means
getManagedDestination validates that a destination path exists, is a string, and resolves inside the adapter-derived trusted root before any read/write/remove operation on managed files. If destinationPath is missing, empty, or not a string, the library refuses the named action rather than operating on an undefined location. This is a path-traversal / safety guard: install state is treated as untrusted input.
Solutions
- Ensure every operation passed to the lifecycle functions has a non-empty string destinationPath; fix or regenerate the install-state record.
- Check that the field name is exactly destinationPath (not dest/path/target) in the state or operation object.
- Validate the operation object with a schema (e.g. Zod) before invoking lifecycle functions so missing paths fail early with a clear message.
- If the operation genuinely has no destination, do not route it through destination-path-requiring functions.
Example fix
// before
applyOperation({ kind: 'copy-file', sourceRelativePath: 'agents/foo.md' })
// after
applyOperation({ kind: 'copy-file', sourceRelativePath: 'agents/foo.md', destinationPath: '~/.claude/agents/foo.md' }) Defensive patterns
Strategy: validation
Validate before calling
function assertDestination(op) {
if (typeof op.destinationPath !== 'string' || op.destinationPath.length === 0) {
throw new Error(`Operation ${op.kind} is missing a non-empty string destinationPath`);
}
} Type guard
function hasDestination(op) {
return op && typeof op.destinationPath === 'string' && op.destinationPath.length > 0;
} Try / catch
try {
await applyOperation(op);
} catch (err) {
if (/missing destination path/.test(err.message)) {
console.error(`Operation ${op.kind} lacks destinationPath — regenerate install-state.`);
} else throw err;
} Prevention
- Validate install-state against a schema requiring destinationPath: string, non-empty, before applying operations.
- Never hand-edit install-state field names; regenerate state via the official install flow.
- Route only destination-bearing operation kinds through path-requiring lifecycle functions.
When it happens
Trigger: Calling any lifecycle function (initialDestination, finalDestination, liveDestination, managedDestination, currentValue, ensureContainedParentDir) with an operation whose destinationPath is undefined, null, empty string, or a non-string — e.g. an install-state record missing the destinationPath key, or code building an operation object without it.
Common situations: Hand-written or tool-generated install state that omitted destinationPath; a rename/refactor changing the field name (e.g. dest/path) without updating state files; an operation for a kind that has no destination (like update-claude-settings) passed to a path-requiring code path.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- a claim token is required
- An install component ID is required
- cannot upload, file does not exist
- claim requires an owner.
- --config-dir must be an existing absolute directory.
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/2dbed32ec08d7be5.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/install-lifecycle.js:338
return parseJsonLikeValue(operation[key], `${operation.kind}.${key}`);
}
}
return undefined;
}
function formatJson(value) {
return `${JSON.stringify(value, null, 2)}\n`;
}
function getManagedDestination(
destinationPath,
trustedRoot,
action,
{ allowFinalSymlink = false } = {}
) {
if (!destinationPath || typeof destinationPath !== 'string') {
throw new Error(`Refusing to ${action}: missing destination path.`);
}
const canonicalRoot = assertWithinTrustedRoot(trustedRoot, trustedRoot, action);
const resolvedDestination = path.resolve(destinationPath);
const canonicalParent = assertWithinTrustedRoot(
path.dirname(resolvedDestination),
canonicalRoot,
action
);
const managedPath = path.join(canonicalParent, path.basename(resolvedDestination));
let stat = null;
try {
stat = fs.lstatSync(managedPath);
} catch (error) {
if (!error || (error.code !== 'ENOENT' && error.code !== 'ENOTDIR')) {
throw error;
}View on GitHub (pinned to 8321021c54)