coleam00/Archon · error · AppPrivateKeyError

Failed to read GITHUB_APP_PRIVATE_KEY_PATH (${path}): ${(err

Error message

Failed to read GITHUB_APP_PRIVATE_KEY_PATH (${path}): ${(err as Error).message}

What it means

loadAppPrivateKey reads the PEM file at GITHUB_APP_PRIVATE_KEY_PATH and wraps any read/parse failure into AppPrivateKeyError, preserving the original error message and cause. This distinguishes file-access problems from the missing-variable case.

Source

Thrown at packages/core/src/github-auth/private-key.ts:40

    // encoded. Both `\\n` (two-char escape from a quoted .env value) and
    // `\\r\\n` (Windows-edited .env) collapse to real `\n`.
    const normalized = inline.replace(/\\r\\n|\\n/g, '\n').replace(/\r\n/g, '\n');
    assertLooksLikePem(normalized);
    return normalized;
  }
  const path = env.GITHUB_APP_PRIVATE_KEY_PATH;
  if (path?.trim()) {
    try {
      const raw = readFileSync(path, 'utf8');
      // Windows-edited .pem files arrive with CRLF; OpenSSL tolerates it but
      // some SSH-style key parsers don't. Normalise so downstream JWT signing
      // never has to care.
      const contents = raw.replace(/\r\n/g, '\n');
      assertLooksLikePem(contents);
      return contents;
    } catch (err) {
      if (err instanceof AppPrivateKeyError) throw err;
      throw new AppPrivateKeyError(
        `Failed to read GITHUB_APP_PRIVATE_KEY_PATH (${path}): ${(err as Error).message}`,
        err
      );
    }
  }
  throw new AppPrivateKeyError(
    'GITHUB_APP_ID is set but no private key was provided. ' +
      'Set GITHUB_APP_PRIVATE_KEY (inline PEM) or GITHUB_APP_PRIVATE_KEY_PATH (path to .pem).'
  );
}

function assertLooksLikePem(s: string): void {
  if (!s.includes('BEGIN') || !s.includes('PRIVATE KEY') || !s.includes('END')) {
    throw new AppPrivateKeyError(
      'Provided value is not a valid PEM-encoded private key (missing BEGIN/END markers).'
    );
  }
}

View on GitHub (pinned to 0773b97458)

Solutions

  1. Verify the path exists and is readable: run `ls -l $(echo $GITHUB_APP_PRIVATE_KEY_PATH)`
  2. Use an absolute path for GITHUB_APP_PRIVATE_KEY_PATH
  3. Fix file permissions (chmod 600, chown to the running user) or fix the container mount
  4. Prefer GITHUB_APP_PRIVATE_KEY with inline PEM if file mounting is problematic

Example fix

// before
GITHUB_APP_PRIVATE_KEY_PATH=./key.pem
// after
GITHUB_APP_PRIVATE_KEY_PATH=/etc/archon/github-app.pem  # absolute, readable by service user
Defensive patterns

Strategy: validation

Validate before calling

const p = process.env.GITHUB_APP_PRIVATE_KEY_PATH;
if (!p) throw new Error('GITHUB_APP_PRIVATE_KEY_PATH is not set');
await fs.access(p, fs.constants.R_OK);

Try / catch

try { const key = await loadAppPrivateKey(env); } catch (e) { if (e instanceof AppPrivateKeyError) { console.error(e.message); process.exit(1); } throw e; }

Prevention

When it happens

Trigger: GITHUB_APP_PRIVATE_KEY_PATH points to a nonexistent file, a directory, or a file the process cannot read (permissions), causing fs read to throw inside loadAppPrivateKey.

Common situations: Typo in the path; relative path resolved from the wrong working directory; Docker mount missing the .pem; key file owned by root with 600 perms; PEM contents corrupted (caught separately by the PEM check).

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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