{"record":{"id":"9b7ee38981939257","repo":"coleam00/Archon","slug":"failed-to-read-github-app-private-key-path-path","errorCode":null,"errorMessage":"Failed to read GITHUB_APP_PRIVATE_KEY_PATH (${path}): ${(err as Error).message}","messagePattern":"Failed to read GITHUB_APP_PRIVATE_KEY_PATH \\((.+?)\\): (.+?)","errorType":"exception","errorClass":"AppPrivateKeyError","httpStatus":null,"severity":"error","filePath":"packages/core/src/github-auth/private-key.ts","lineNumber":40,"sourceCode":"    // encoded. Both `\\\\n` (two-char escape from a quoted .env value) and\n    // `\\\\r\\\\n` (Windows-edited .env) collapse to real `\\n`.\n    const normalized = inline.replace(/\\\\r\\\\n|\\\\n/g, '\\n').replace(/\\r\\n/g, '\\n');\n    assertLooksLikePem(normalized);\n    return normalized;\n  }\n  const path = env.GITHUB_APP_PRIVATE_KEY_PATH;\n  if (path?.trim()) {\n    try {\n      const raw = readFileSync(path, 'utf8');\n      // Windows-edited .pem files arrive with CRLF; OpenSSL tolerates it but\n      // some SSH-style key parsers don't. Normalise so downstream JWT signing\n      // never has to care.\n      const contents = raw.replace(/\\r\\n/g, '\\n');\n      assertLooksLikePem(contents);\n      return contents;\n    } catch (err) {\n      if (err instanceof AppPrivateKeyError) throw err;\n      throw new AppPrivateKeyError(\n        `Failed to read GITHUB_APP_PRIVATE_KEY_PATH (${path}): ${(err as Error).message}`,\n        err\n      );\n    }\n  }\n  throw new AppPrivateKeyError(\n    'GITHUB_APP_ID is set but no private key was provided. ' +\n      'Set GITHUB_APP_PRIVATE_KEY (inline PEM) or GITHUB_APP_PRIVATE_KEY_PATH (path to .pem).'\n  );\n}\n\nfunction assertLooksLikePem(s: string): void {\n  if (!s.includes('BEGIN') || !s.includes('PRIVATE KEY') || !s.includes('END')) {\n    throw new AppPrivateKeyError(\n      'Provided value is not a valid PEM-encoded private key (missing BEGIN/END markers).'\n    );\n  }\n}","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/coleam00/Archon/blob/0773b9745896ef0612e709c80845a0f7db315b19/packages/core/src/github-auth/private-key.ts#L22-L58","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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"],"exampleFix":"// before\nGITHUB_APP_PRIVATE_KEY_PATH=./key.pem\n// after\nGITHUB_APP_PRIVATE_KEY_PATH=/etc/archon/github-app.pem  # absolute, readable by service user","handlingStrategy":"validation","validationCode":"const p = process.env.GITHUB_APP_PRIVATE_KEY_PATH;\nif (!p) throw new Error('GITHUB_APP_PRIVATE_KEY_PATH is not set');\nawait fs.access(p, fs.constants.R_OK);","typeGuard":null,"tryCatchPattern":"try { const key = await loadAppPrivateKey(env); } catch (e) { if (e instanceof AppPrivateKeyError) { console.error(e.message); process.exit(1); } throw e; }","preventionTips":["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)"],"tags":["filesystem","configuration","github-app","pem"],"backgroundTag":"file-read-failed","analyzedSha":"0773b9745896ef0612e709c80845a0f7db315b19","analyzedAt":"2026-09-01T02:28:07.064Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}