{"record":{"id":"2e84ef5bc4f5a6cd","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":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/path-safety.js","lineNumber":87,"sourceCode":"function isWithinRoot(target, root) {\n  if (!root) {\n    return false;\n  }\n\n  try {\n    return resolveContainment(target, root).contained;\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Fail-closed guard: throw unless `target` is contained within `root`.\n * Returns the canonicalized target path on success.\n */\nfunction assertWithinTrustedRoot(target, root, action = 'write') {\n  if (!target || typeof target !== 'string') {\n    throw new Error(`Refusing to ${action}: missing destination path.`);\n  }\n  if (!root) {\n    throw new Error(`Refusing to ${action} '${target}': no trusted install root resolved.`);\n  }\n\n  let containment;\n  try {\n    containment = resolveContainment(target, root);\n  } catch {\n    containment = null;\n  }\n  if (!containment || !containment.contained) {\n    throw new Error(`Refusing to ${action} outside the install root: '${target}' is not within '${root}'.`);\n  }\n  return containment.realTarget;\n}\n\nmodule.exports = {","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/path-safety.js#L69-L105","documentation":"assertWithinTrustedRoot() is a fail-closed path-containment guard: it verifies a target path is inside a trusted install root before allowing a write/repair operation. Its first check rejects a target that is missing, not a string, or empty, with this error naming the intended action. The library refuses to proceed rather than guessing a destination for a filesystem mutation.","triggerScenarios":"Calling assertWithinTrustedRoot(''), assertWithinTrustedRoot(undefined), assertWithinTrustedRoot(null), or a non-string at the target slot — usually via helpers like validatedNext/canonicalRoot when the computed destination path resolved to nothing (failed path join, missing config field, empty variable).","commonSituations":"Install/repair scripts where a config key holding the destination is blank; path.join producing '' because a segment was undefined; refactors renaming a config field so the old lookup returns undefined; calling the guard before the destination is actually computed.","solutions":["Pass the fully resolved destination string as the first argument; log the value just before the call to see why it is empty.","Fix the upstream path construction (missing config key, undefined variable, wrong join order) so a real path is produced.","Check the action argument in the message ('write', 'repair', ...) to identify which call site sent the empty target.","Add an explicit early check that the destination is a non-empty string with a domain-specific message before invoking the guard."],"exampleFix":"// before\nconst target = cfg.install?.target; // undefined\nassertWithinTrustedRoot(target, root, 'write');\n// after\nconst target = cfg.install?.target;\nif (!target) throw new Error('install.target is not configured');\nassertWithinTrustedRoot(target, root, 'write');","handlingStrategy":"validation","validationCode":"if (typeof target !== 'string' || target.length === 0) {\n  throw new Error(`Destination path not resolved for action '${action}': ${JSON.stringify(target)}`);\n}\nassertWithinTrustedRoot(target, root, action);","typeGuard":"function isNonEmptyPath(v) {\n  return typeof v === 'string' && v.trim().length > 0;\n}","tryCatchPattern":"try {\n  const real = assertWithinTrustedRoot(target, root, 'write');\n} catch (e) {\n  if (/missing destination path/.test(e.message)) {\n    console.error('Destination construction failed; check the config field feeding the target.');\n  } else throw e;\n}","preventionTips":["Compute destination paths before invoking containment guards, not inside them.","Validate config-driven path fields at config load time.","Log path values once during setup to catch undefined/empty joins early.","Use a single path-building helper so a missing segment fails in one obvious place."],"tags":["validation","path-safety","empty-argument","filesystem"],"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"}