affaan-m/ECC · error

Nasiko cannot install directly into a filesystem root.

Error message

Nasiko cannot install directly into a filesystem root.

What it means

validateInstallDirectory resolves the requested path and refuses a path equal to the filesystem root (e.g. / on POSIX, C:\ on Windows). Installing directly into a root would scatter binaries and directories at the top level of a volume, so it is blocked. A non-root error ('no resolvable filesystem ancestor') exists for the opposite case of a path whose ancestors are all unresolvable.

Solutions

  1. Choose a real subdirectory, e.g. /usr/local/bin or C:\\Users\\me\\nasiko\\bin.
  2. Fix the templating/script bug where the directory component was dropped and only the root remained.
  3. Add a guard in your wrapper that rejects root paths before delegating to the library.
  4. If a config file specifies the root, edit it to a concrete absolute subpath.

Example fix

// before
const dir = process.env.NASIKO_PREFIX || '/';
await installDirectory({ dir });
// after
const dir = process.env.NASIKO_PREFIX || '/usr/local/bin';
if (path.resolve(dir) === path.parse(path.resolve(dir)).root) throw new Error('Refusing filesystem root install dir.');
await installDirectory({ dir });
Defensive patterns

Strategy: validation

Validate before calling

const r = path.resolve(dir); if (r === path.parse(r).root) throw new Error('Install dir must be a subdirectory, not a filesystem root.');

Type guard

const isNonRootDir = (d) => { const r = path.resolve(d); return r !== path.parse(r).root; };

Try / catch

try { await installDirectory({ dir }); } catch (err) { if (err.message.includes('filesystem root')) throw new Error('Refusing root install; pass a concrete subdirectory.'); throw err; }

Prevention

When it happens

Trigger: Calling installDirectory, parseMutationArguments, candidate, or parseStatusArguments with --dir / or --dir C:\\ (or any drive root), so path.resolve(dir) === path.parse(resolved).root.

Common situations: CLI users typing '--dir /' as shorthand for 'system-wide'; scripts parameterized with an empty suffix (prefix + '' collapses to root); config defaulting to a bare drive letter on Windows.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/c8537e5f10d4bf02. Report an issue: GitHub.

Appendix: source

Thrown at scripts/lib/nasiko-release.js:173

    });
    request.setTimeout(options.timeoutMs || 15000, () => request.destroy(new Error('Nasiko registry request timed out.')));
    request.on('error', reject);
  });
}

function defaultInstallDirectory(normalized, environment = process.env, homeDirectory = os.homedir()) {
  if (normalized.os === 'windows') {
    if (!environment.LOCALAPPDATA) throw new Error('LOCALAPPDATA is required on Windows.');
    return path.join(environment.LOCALAPPDATA, 'nasiko', 'bin');
  }
  return path.join(homeDirectory, '.local', 'bin');
}

function validateInstallDirectory(directory) {
  if (typeof directory !== 'string' || directory.includes('\0') || !path.isAbsolute(directory)) throw new Error('Nasiko install directory must be an absolute path.');
  if (/^(?:\\\\|\\\\\?\\|\\\\\.\\)/.test(directory)) throw new Error('Nasiko install directory must be on a local filesystem.');
  const resolved = path.resolve(directory);
  if (resolved === path.parse(resolved).root) throw new Error('Nasiko cannot install directly into a filesystem root.');
  let ancestor = resolved;
  while (!fs.existsSync(ancestor)) {
    const parent = path.dirname(ancestor);
    if (parent === ancestor) throw new Error('Nasiko install directory has no resolvable filesystem ancestor.');
    ancestor = parent;
  }
  const canonical = fs.realpathSync(ancestor);
  return path.join(canonical, path.relative(ancestor, resolved));
}

function assertPrivateInstallDirectory(directory) {
  const stats = fs.lstatSync(directory);
  if (!stats.isDirectory() || stats.isSymbolicLink()) throw new Error('Nasiko install directory must be a real directory, not a symlink.');
  if (process.platform !== 'win32') {
    if (typeof process.getuid === 'function' && stats.uid !== process.getuid()) throw new Error('Nasiko install directory must be owned by the current user.');
    if ((stats.mode & 0o022) !== 0) throw new Error('Nasiko install directory must not be group- or world-writable.');
  }
}

View on GitHub (pinned to 8321021c54)