{"record":{"id":"64352ccd4ae4cdfc","repo":"affaan-m/ECC","slug":"nasiko-install-directory-must-be-an-absolute-path","errorCode":null,"errorMessage":"Nasiko install directory must be an absolute path.","messagePattern":"Nasiko install directory must be an absolute path\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/nasiko-release.js","lineNumber":142,"sourceCode":"      });\n      response.on('end', () => resolve(Buffer.concat(chunks)));\n      response.on('error', reject);\n    });\n    request.setTimeout(options.timeoutMs || 15000, () => request.destroy(new Error('Nasiko registry request timed out.')));\n    request.on('error', reject);\n  });\n}\n\nfunction defaultInstallDirectory(normalized, environment = process.env, homeDirectory = os.homedir()) {\n  if (normalized.os === 'windows') {\n    if (!environment.LOCALAPPDATA) throw new Error('LOCALAPPDATA is required on Windows.');\n    return path.join(environment.LOCALAPPDATA, 'nasiko', 'bin');\n  }\n  return path.join(homeDirectory, '.local', 'bin');\n}\n\nfunction validateInstallDirectory(directory) {\n  if (typeof directory !== 'string' || directory.includes('\\0') || !path.isAbsolute(directory)) throw new Error('Nasiko install directory must be an absolute path.');\n  if (/^(?:\\\\\\\\|\\\\\\\\\\?\\\\|\\\\\\\\\\.\\\\)/.test(directory)) throw new Error('Nasiko install directory must be on a local filesystem.');\n  const resolved = path.resolve(directory);\n  if (resolved === path.parse(resolved).root) throw new Error('Nasiko cannot install directly into a filesystem root.');\n  let ancestor = resolved;\n  while (!fs.existsSync(ancestor)) {\n    const parent = path.dirname(ancestor);\n    if (parent === ancestor) throw new Error('Nasiko install directory has no resolvable filesystem ancestor.');\n    ancestor = parent;\n  }\n  const canonical = fs.realpathSync(ancestor);\n  return path.join(canonical, path.relative(ancestor, resolved));\n}\n\nfunction assertPrivateInstallDirectory(directory) {\n  const stats = fs.lstatSync(directory);\n  if (!stats.isDirectory() || stats.isSymbolicLink()) throw new Error('Nasiko install directory must be a real directory, not a symlink.');\n  if (process.platform !== 'win32') {\n    if (typeof process.getuid === 'function' && stats.uid !== process.getuid()) throw new Error('Nasiko install directory must be owned by the current user.');","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/affaan-m/ECC/blob/06c5e118c4d3e6c3b7f9445f973a2194c82de193/scripts/lib/nasiko-release.js#L124-L160","documentation":"validateInstallDirectory in scripts/lib/nasiko-release.js is the first gate on caller-supplied install paths: the value must be a string, contain no NUL bytes, and be absolute (path.isAbsolute). Relative or malformed input is rejected before any filesystem work happens. The subsequent checks (local filesystem, not a root, resolvable ancestor) run only after this passes.","triggerScenarios":"Passing directory: '~/.local/bin' (tilde is not expanded by Node, so it is relative), './bin', 'nasiko/bin', undefined, a non-string value, or a string containing a NUL character.","commonSituations":"Shell-style paths copied into JS configs where '~' is never expanded; config files with relative paths that worked with other tools (which expand or chdir first); templating bugs injecting empty strings; values sourced from JSON that arrive as null.","solutions":["Expand and resolve before calling: `path.resolve(rawDir.replace(/^~(?=[/\\\\]|$)/, os.homedir()))`","Use path.join(os.homedir(), '.local', 'bin') or another constructed absolute path","Validate config inputs with a schema that requires an absolute path string"],"exampleFix":"// before: tilde is relative to Node, not the shell\ninstallNasiko({ directory: '~/.local/bin' }); // throws\n// after\ninstallNasiko({ directory: path.join(os.homedir(), '.local', 'bin') });","handlingStrategy":"validation","validationCode":"const fs = require('fs');\nconst os = require('os');\nconst path = require('path');\n\nfunction toInstallDir(raw) {\n  const expanded = raw.replace(/^~(?=[/\\\\]|$)/, os.homedir());\n  const dir = path.resolve(expanded);\n  if (!path.isAbsolute(dir)) throw new Error(`Install directory must be absolute: ${raw}`);\n  return dir;\n}","typeGuard":"const isAbsoluteLocalPath = (p: unknown): p is string =>\n  typeof p === 'string' && !p.includes('\\0') && path.isAbsolute(p);","tryCatchPattern":"try {\n  await installNasiko({ directory: configuredDir });\n} catch (error) {\n  if (/must be an absolute path/.test(String(error.message))) {\n    // Expand '~' and resolve relatives before retrying; schema-validate config.\n  }\n  throw error;\n}","preventionTips":["Never pass shell-style '~' paths into Node APIs; expand with os.homedir() first","Schema-validate user config: directory must be a non-empty absolute path string","Centralize path normalization in one helper used by all installer callers"],"tags":["path","validation","install"],"backgroundTag":"path-validation-failed","analyzedSha":"06c5e118c4d3e6c3b7f9445f973a2194c82de193","analyzedAt":"2026-08-18T11:27:13.915Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}