{"record":{"id":"5ea1b260f529ded9","repo":"affaan-m/ECC","slug":"nasiko-install-directory-must-be-on-a-local-filesy","errorCode":null,"errorMessage":"Nasiko install directory must be on a local filesystem.","messagePattern":"Nasiko install directory must be on a local filesystem\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/nasiko-release.js","lineNumber":143,"sourceCode":"      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.');\n    if ((stats.mode & 0o022) !== 0) throw new Error('Nasiko install directory must not be group- or world-writable.');","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/affaan-m/ECC/blob/06c5e118c4d3e6c3b7f9445f973a2194c82de193/scripts/lib/nasiko-release.js#L125-L161","documentation":"The second gate in validateInstallDirectory rejects Windows UNC paths (\\\\server\\share...) and Win32 device-namespace prefixes (\\\\?\\, \\\\.\\) via a leading-backslash pattern check. The installer only writes to local filesystems so that atomic-rename semantics, permissions, and symlink behavior are predictable. Network shares are explicitly out of scope.","triggerScenarios":"Passing directory: '\\\\\\\\fileserver\\\\builds\\\\nasiko' (UNC), or a long-path/device form beginning with '\\\\\\\\?\\\\' or '\\\\\\\\.\\\\'. These start with backslashes and match the reject pattern even though path.isAbsolute() considers them absolute on Windows.","commonSituations":"Corporate CI configs pointing at SMB/NAS shares; users putting tools on mapped-by-UNC home directories; developers attempting to sidestep MAX_PATH with the \\\\?\\ prefix.","solutions":["Install to a local directory such as the LOCALAPPDATA default or C:\\tools\\nasiko\\bin","Map the share to a drive letter (net use N: \\\\fileserver\\builds) and pass N:\\nasiko\\bin if a share must be involved - or better, install locally and copy","Remove \\\\?\\ / \\\\.\\ prefixes from configured paths"],"exampleFix":"// before: UNC share passed directly\ninstallNasiko({ directory: String.raw`\\\\fileserver\\builds\\nasiko\\bin` }); // throws\n// after: local path\ninstallNasiko({ directory: path.join(env.LOCALAPPDATA, 'nasiko', 'bin') });","handlingStrategy":"validation","validationCode":"function isLocalAbsolutePath(dir) {\n  // Rejects UNC (\\\\server\\share) and device (\\\\?\\, \\\\.\\) prefixes.\n  return path.isAbsolute(dir) && !dir.startsWith(String.raw`\\\\`);\n}\nif (!isLocalAbsolutePath(configuredDir)) {\n  throw new Error('Install directory must be a local absolute path, not a UNC/device path');\n}","typeGuard":"const isLocalAbsoluteWindowsPath = (p: string): boolean =>\n  /^[A-Za-z]:[\\\\/]/.test(p) && !p.startsWith(String.raw`\\\\`);","tryCatchPattern":"try {\n  await installNasiko({ directory: configuredDir });\n} catch (error) {\n  if (/must be on a local filesystem/.test(String(error.message))) {\n    // Map the share to a drive letter or choose a local directory, then retry.\n  }\n  throw error;\n}","preventionTips":["Default to %LOCALAPPDATA%\\nasiko\\bin or another local path in configs","Strip \\\\?\\ long-path prefixes from user-supplied directories","Reject UNC inputs in config validation so the installer never sees them"],"tags":["windows","unc","network-share","path","install"],"backgroundTag":"network-path-unsupported","analyzedSha":"06c5e118c4d3e6c3b7f9445f973a2194c82de193","analyzedAt":"2026-08-18T11:27:13.915Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}