{"record":{"id":"f87cda1f0ef4d014","repo":"coleam00/Archon","slug":"github-adapter-misconfigured-both-app-mode-githu","errorCode":null,"errorMessage":"GitHub adapter misconfigured: both App mode (GITHUB_APP_ID) and PAT mode (GITHUB_TOKEN) are configured. Pick one — unset GITHUB_TOKEN for App mode, or unset GITHUB_APP_ID for PAT mode.","messagePattern":"GitHub adapter misconfigured: both App mode \\(GITHUB_APP_ID\\) and PAT mode \\(GITHUB_TOKEN\\) are configured\\. Pick one — unset GITHUB_TOKEN for App mode, or unset GITHUB_APP_ID for PAT mode\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"packages/server/src/index.ts","lineNumber":415,"sourceCode":"  let github: GitHubAdapter | null = null;\n  let githubAppAuthProvider: IGitHubAppAuthProvider | null = null;\n  let gitea: GiteaAdapter | null = null;\n  let gitlab: GitLabAdapter | null = null;\n  let discord: DiscordAdapter | null = null;\n  let slack: SlackAdapter | null = null;\n  let slackBridge: SlackWorkflowBridge | null = null;\n\n  if (!opts.skipPlatformAdapters) {\n    // Check that at least one platform is configured\n    const hasTelegram = Boolean(process.env.TELEGRAM_BOT_TOKEN);\n    const hasDiscord = Boolean(process.env.DISCORD_BOT_TOKEN);\n    // GitHub adapter: dual-mode (App vs PAT). Fail fast if both are configured —\n    // silently preferring one would create 3am debugging sessions for an operator\n    // who copy-pasted half a config and didn't realise the other half was already\n    // set in /etc/archon/.env. (PRD: \"fail-fast on misconfig\".)\n    const ghAuthMode = selectGitHubAuthMode(process.env);\n    if (ghAuthMode.kind === 'conflict') {\n      throw new Error(ghAuthMode.message);\n    }\n    const hasGitHub = ghAuthMode.kind !== 'none';\n    const hasGitea = Boolean(\n      process.env.GITEA_URL && process.env.GITEA_TOKEN && process.env.GITEA_WEBHOOK_SECRET\n    );\n    const hasGitLab = Boolean(process.env.GITLAB_TOKEN && process.env.GITLAB_WEBHOOK_SECRET);\n\n    if (!hasTelegram && !hasDiscord && !hasGitHub && !hasGitea && !hasGitLab) {\n      getLog().warn('no_platform_adapters_configured');\n    }\n\n    if (ghAuthMode.kind === 'app') {\n      // Locals avoid `!` non-null assertions: hasGitHubApp already guarantees\n      // GITHUB_APP_ID and WEBHOOK_SECRET are set, but the linter can't infer that.\n      const appId = process.env.GITHUB_APP_ID;\n      const webhookSecret = process.env.WEBHOOK_SECRET;\n      if (!appId || !webhookSecret) {\n        throw new Error('GitHub App mode misconfigured: GITHUB_APP_ID and WEBHOOK_SECRET required');","sourceCodeStart":397,"sourceCodeEnd":433,"githubUrl":"https://github.com/coleam00/Archon/blob/0773b9745896ef0612e709c80845a0f7db315b19/packages/server/src/index.ts#L397-L433","documentation":"startServer fail-fast check for the GitHub adapter's dual authentication modes: App mode (GITHUB_APP_ID) and PAT mode (GITHUB_TOKEN). selectGitHubAuthMode() returns a 'conflict' result when both are present, and startServer throws rather than silently preferring one, because an operator who copied half a config wouldn't know which credential is actually being used.","triggerScenarios":"The server environment (e.g. /etc/archon/.env) defines both GITHUB_APP_ID and GITHUB_TOKEN when `serveCommand` calls startServer.","commonSituations":"An operator previously ran PAT mode and later added GitHub App credentials (or vice versa) without removing the old variable; copy-pasting a full example .env that contains both blocks; migrating from PAT to App mode per docs and forgetting `unset GITHUB_TOKEN`.","solutions":["Remove/comment GITHUB_TOKEN from the env file to run in GitHub App mode, or remove GITHUB_APP_ID (+ its App-only vars) to run in PAT mode.","Run `archon setup` to reconfigure the GitHub adapter cleanly so only one mode's variables are written.","Inspect the resolved environment (`printenv | grep GITHUB`) in the actual process context (systemd unit, container) — the conflict may come from a second env source.","Restart the server after unsetting the variable; startup env is only read once."],"exampleFix":"# before (.env)\nGITHUB_APP_ID=Iv1.xxxx\nGITHUB_TOKEN=ghp_xxx\n# after: App mode only\nGITHUB_APP_ID=Iv1.xxxx\n# GITHUB_TOKEN removed","handlingStrategy":"validation","validationCode":"const vars = readEnvFiles(['/etc/archon/.env']);\nconst both = Boolean(vars.GITHUB_APP_ID) && Boolean(vars.GITHUB_TOKEN);\nif (both) throw new Error('Unset GITHUB_TOKEN (App mode) or GITHUB_APP_ID (PAT mode) before starting.');","typeGuard":null,"tryCatchPattern":"try {\n  await startServer(config);\n} catch (e) {\n  if (/both App mode .* and PAT mode .* are configured/i.test(e?.message ?? '')) {\n    logFatal('GitHub adapter misconfigured: keep only GITHUB_APP_ID or GITHUB_TOKEN.');\n    process.exit(1);\n  }\n  throw e;\n}","preventionTips":["Keep one canonical .env per deployment and remove dead variables during migrations.","After switching auth modes, grep the env for leftover GITHUB_* variables.","Document that PAT-to-App migration must delete GITHUB_TOKEN.","Check container/systemd env sources, not just the .env file."],"tags":["configuration","github","env","fail-fast","startup"],"backgroundTag":"conflicting-env-config","analyzedSha":"0773b9745896ef0612e709c80845a0f7db315b19","analyzedAt":"2026-09-01T02:28:07.064Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}