{"record":{"id":"8fd6d9fa69414199","repo":"coleam00/Archon","slug":"github-app-id-is-set-but-no-private-key-was-provid","errorCode":null,"errorMessage":"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).","messagePattern":"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\\)\\.","errorType":"exception","errorClass":"AppPrivateKeyError","httpStatus":null,"severity":"error","filePath":"packages/core/src/github-auth/private-key.ts","lineNumber":46,"sourceCode":"  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}\n","sourceCodeStart":28,"sourceCodeEnd":59,"githubUrl":"https://github.com/coleam00/Archon/blob/0773b9745896ef0612e709c80845a0f7db315b19/packages/core/src/github-auth/private-key.ts#L28-L59","documentation":"loadAppPrivateKey requires a private key when GITHUB_APP_ID is set. If neither GITHUB_APP_PRIVATE_KEY (inline PEM) nor GITHUB_APP_PRIVATE_KEY_PATH is provided, it throws this AppPrivateKeyError listing both accepted variables.","triggerScenarios":"Setting GITHUB_APP_ID but omitting both GITHUB_APP_PRIVATE_KEY and GITHUB_APP_PRIVATE_KEY_PATH in the environment, then calling loadAppPrivateKey.","commonSituations":"Partial migration from PAT auth to GitHub App auth; .env file missing the key vars; secret not injected in CI/container; typo in the env var name.","solutions":["Set GITHUB_APP_PRIVATE_KEY to the PEM contents (with \\n escapes) or GITHUB_APP_PRIVATE_KEY_PATH to the .pem file","Check the .env / secret manager actually exports the variable into the process","Unset GITHUB_APP_ID if you do not intend to use GitHub App authentication at all"],"exampleFix":"// before\nGITHUB_APP_ID=123456\n// after\nGITHUB_APP_ID=123456\nGITHUB_APP_PRIVATE_KEY_PATH=/etc/archon/github-app.pem","handlingStrategy":"validation","validationCode":"if (process.env.GITHUB_APP_ID && !process.env.GITHUB_APP_PRIVATE_KEY && !process.env.GITHUB_APP_PRIVATE_KEY_PATH) {\n  throw new Error('GITHUB_APP_ID set without GITHUB_APP_PRIVATE_KEY or GITHUB_APP_PRIVATE_KEY_PATH');\n}","typeGuard":null,"tryCatchPattern":"try { const key = await loadAppPrivateKey(process.env); } catch (e) { if (e instanceof AppPrivateKeyError) failStartupWithConfigHelp(e); throw e; }","preventionTips":["Validate the full GitHub App env var set (ID + key) together at config load time","Keep both variables in the same .env / secret bundle so they ship together","Fail fast at startup with a config checklist rather than at first use"],"tags":["configuration","env-var","github-app","missing-secret"],"backgroundTag":"missing-env-var","analyzedSha":"0773b9745896ef0612e709c80845a0f7db315b19","analyzedAt":"2026-09-01T02:28:07.064Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}