coleam00/Archon · error

Failed to read version: ${err.message}

Error message

Failed to read version: ${err.message}

What it means

getDevVersion's catch-all: after the specialized ENOENT and EACCES branches, any other readFile failure is rethrown with the original Node error message prefixed with 'Failed to read version:'. It preserves the underlying evidence (e.g. EISDIR, ELOOP, EMFILE) while giving it version-command context.

Source

Thrown at packages/cli/src/commands/version.ts:46

/**
 * Get version for development mode (reads package.json)
 */
async function getDevVersion(): Promise<{ name: string; version: string }> {
  // Read root package.json (monorepo version), not the CLI package's own
  const pkgPath = join(SCRIPT_DIR, '../../../../package.json');

  let content: string;
  try {
    content = await readFile(pkgPath, 'utf-8');
  } catch (error) {
    const err = error as NodeJS.ErrnoException;
    if (err.code === 'ENOENT') {
      throw new Error('Failed to read version: package.json not found (bad installation?)');
    } else if (err.code === 'EACCES') {
      throw new Error('Failed to read version: permission denied reading package.json');
    }
    throw new Error(`Failed to read version: ${err.message}`);
  }

  let pkg: PackageJson;
  try {
    pkg = JSON.parse(content) as PackageJson;
  } catch (_error) {
    throw new Error('Failed to read version: package.json is malformed');
  }

  return { name: pkg.name, version: pkg.version };
}

/**
 * Get the git commit hash at runtime (dev mode).
 * Returns 'unknown' if git is unavailable or the command fails.
 */
async function getDevGitCommit(): Promise<string> {
  try {

View on GitHub (pinned to 0773b97458)

Solutions

  1. Read the wrapped err.message to identify the errno (EISDIR, ELOOP, EMFILE...) and fix that specific condition.
  2. If EISDIR: remove/rename the directory that is occupying the package.json path and restore the real file via reinstall.
  3. If ELOOP: repair the symlink chain in the install path (reinstall is simplest).
  4. If EMFILE/ENFILE: raise the fd limit (`ulimit -n`) or close leaking processes, then retry.

Example fix

// before
$ ls -la /opt/archon/lib/package.json
drwxr-xr-x 2 user user 4096 package.json   # directory shadowing the file -> EISDIR
// after
$ rm -r /opt/archon/lib/package.json && bun install -g @archon/cli   # reinstall restores the real file
Defensive patterns

Strategy: try-catch

Validate before calling

import { lstatSync } from 'node:fs';
const st = lstatSync(pkgPath, { throwIfNoEntry: false });
if (st?.isDirectory()) {
  throw new Error(`${pkgPath} is a directory (EISDIR): remove it and reinstall to restore the real package.json`);
}

Try / catch

try {
  const info = await devInfo();
} catch (err) {
  if (err instanceof Error && err.message.startsWith('Failed to read version:') && !err.message.includes('not found') && !err.message.includes('permission denied')) {
    // err.message carries the raw errno (EISDIR/ELOOP/EMFILE...);
    // fix that specific OS condition, most often via reinstall.
  } else throw err;
}

Prevention

When it happens

Trigger: devInfo -> getDevVersion calls readFile(pkgPath) and Node rejects with an errno other than ENOENT/EACCES: EISDIR (a directory named package.json exists), ELOOP (symlink loop), EMFILE/ENFILE (fd exhaustion), EIO (disk error), or an fs layer intercepting the read (e.g. broken FUSE mount).

Common situations: A directory accidentally created named package.json in the install root; a dangling symlink chain in the install path; too many open files from a long-running shell; NFS/FUSE mount failure on a networked install directory.

Related errors


AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01). Data as JSON: /api/errors/fe365b709f1f18d1. Report an issue: GitHub.