{"record":{"id":"2dbed32ec08d7be5","repo":"affaan-m/ECC","slug":"refusing-to-action-missing-destination-path","errorCode":null,"errorMessage":"Refusing to ${action}: missing destination path.","messagePattern":"Refusing to (.+?): missing destination path\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/install-lifecycle.js","lineNumber":232,"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":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/install-lifecycle.js#L214-L250","documentation":"Thrown by getManagedDestination() in scripts/lib/install-lifecycle.js as a safety guard when the destination path for a managed write is missing or not a string. The installer refuses to proceed with an empty destination because it cannot verify the write lands inside the trusted root.","triggerScenarios":"getManagedDestination(destinationPath, trustedRoot, action, opts) where destinationPath is undefined, null, '', or non-string. Reached from copy/merge/symlink operations that forgot to set destinationPath.","commonSituations":"Operation builder omitted destinationPath; a transform returned undefined for the destination; config has a blank path field; programmatic caller passed options.destinationPath from a missing config key.","solutions":["Ensure every operation constructed has a non-empty string destinationPath.","Validate the operation before dispatch: if (!op.destinationPath) throw new Error('destination required').","Trace the operation builder (buildCopyFileOperation / merge op builders) to confirm destinationPath is computed from defined inputs.","Default the destination explicitly when deriving from a config field that may be absent."],"exampleFix":"// before\naddFileCopyOperation(operations, {\n  sourceRoot,\n  sourceRelativePath: 'rules/x.md',\n  destinationPath: options.dest, // undefined when options.dest missing\n});\n\n// after\nif (!options.dest) throw new Error('options.dest is required');\naddFileCopyOperation(operations, {\n  sourceRoot,\n  sourceRelativePath: 'rules/x.md',\n  destinationPath: options.dest,\n});","handlingStrategy":"validation","validationCode":"function hasStringDestination(op) {\n  return op && typeof op.destinationPath === 'string' && op.destinationPath.trim() !== '';\n}\nif (!hasStringDestination(operation)) {\n  throw new Error(`Refusing to ${action}: missing destination path.`);\n}","typeGuard":"function hasDestinationPath(op) {\n  return op != null && typeof op === 'object'\n    && typeof op.destinationPath === 'string'\n    && op.destinationPath.trim() !== '';\n}","tryCatchPattern":"try {\n  return getManagedDestination(destinationPath, trustedRoot, action, opts);\n} catch (err) {\n  if (/missing destination path/.test(err.message)) {\n    throw new Error(`Operation ${operation.kind} missing destinationPath`);\n  }\n  throw err;\n}","preventionTips":["Validate operations at construction time: assert a non-empty destinationPath.","Default destinationPath from defined inputs and fail loudly if absent.","Add a fixture-based test that exercises every operation builder."],"tags":["install","filesystem","safety","operations"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}