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
- Verify the path exists and is readable: run `ls -l $(echo $GITHUB_APP_PRIVATE_KEY_PATH)`
- Use an absolute path for GITHUB_APP_PRIVATE_KEY_PATH
- Fix file permissions (chmod 600, chown to the running user) or fix the container mount
- 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
- Use absolute paths and verify readability at service startup
- Check container/volume mounts include the .pem file
- Confirm the process user can read the key file (chmod 600 + correct owner)
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
- Provided value is not a valid PEM-encoded private key (missi
- GITHUB_APP_ID is set but no private key was provided. Set GI
- GitHub App mode misconfigured: GITHUB_APP_ID and WEBHOOK_SEC
- GitHub App mode is active but the server is bound to a non-l
- No chat in context
AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01).
Data as JSON: /api/errors/9b7ee38981939257.
Report an issue: GitHub.