{"record":{"id":"2dbed32ec08d7be5","repo":"affaan-m/ECC","slug":"refusing-to-action-missing-destination-path-2dbed3","errorCode":null,"errorMessage":"Refusing to ${action}: missing destination path.","messagePattern":"Refusing to (.+?): missing destination path\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/install-lifecycle.js","lineNumber":338,"sourceCode":"      return parseJsonLikeValue(operation[key], `${operation.kind}.${key}`);\n    }\n  }\n\n  return undefined;\n}\n\nfunction formatJson(value) {\n  return `${JSON.stringify(value, null, 2)}\\n`;\n}\n\nfunction getManagedDestination(\n  destinationPath,\n  trustedRoot,\n  action,\n  { allowFinalSymlink = false } = {}\n) {\n  if (!destinationPath || typeof destinationPath !== 'string') {\n    throw new Error(`Refusing to ${action}: missing destination path.`);\n  }\n\n  const canonicalRoot = assertWithinTrustedRoot(trustedRoot, trustedRoot, action);\n  const resolvedDestination = path.resolve(destinationPath);\n  const canonicalParent = assertWithinTrustedRoot(\n    path.dirname(resolvedDestination),\n    canonicalRoot,\n    action\n  );\n  const managedPath = path.join(canonicalParent, path.basename(resolvedDestination));\n  let stat = null;\n\n  try {\n    stat = fs.lstatSync(managedPath);\n  } catch (error) {\n    if (!error || (error.code !== 'ENOENT' && error.code !== 'ENOTDIR')) {\n      throw error;\n    }","sourceCodeStart":320,"sourceCodeEnd":356,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/install-lifecycle.js#L320-L356","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\napplyOperation({ kind: 'copy-file', sourceRelativePath: 'agents/foo.md' })\n\n// after\napplyOperation({ kind: 'copy-file', sourceRelativePath: 'agents/foo.md', destinationPath: '~/.claude/agents/foo.md' })","handlingStrategy":"validation","validationCode":"function assertDestination(op) {\n  if (typeof op.destinationPath !== 'string' || op.destinationPath.length === 0) {\n    throw new Error(`Operation ${op.kind} is missing a non-empty string destinationPath`);\n  }\n}","typeGuard":"function hasDestination(op) {\n  return op && typeof op.destinationPath === 'string' && op.destinationPath.length > 0;\n}","tryCatchPattern":"try {\n  await applyOperation(op);\n} catch (err) {\n  if (/missing destination path/.test(err.message)) {\n    console.error(`Operation ${op.kind} lacks destinationPath — regenerate install-state.`);\n  } else throw err;\n}","preventionTips":["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."],"tags":["path","validation","missing-argument"],"backgroundTag":"missing-required-argument","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}