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

  1. Ensure every operation passed to the lifecycle functions has a non-empty string destinationPath; fix or regenerate the install-state record.
  2. Check that the field name is exactly destinationPath (not dest/path/target) in the state or operation object.
  3. Validate the operation object with a schema (e.g. Zod) before invoking lifecycle functions so missing paths fail early with a clear message.
  4. 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

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


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)