{"record":{"id":"c3051cc2fc41a63f","repo":"paperclipai/paperclip","slug":"github-webhook-configuration-could-not-be-confirme","errorCode":null,"errorMessage":"GitHub webhook configuration could not be confirmed. Reconnect to retry; repository access was not changed.","messagePattern":"GitHub webhook configuration could not be confirmed\\. Reconnect to retry; repository access was not changed\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/chat-github-webhook-config.ts","lineNumber":730,"sourceCode":"      redirect: \"error\",\n      signal: AbortSignal.timeout(25_000),\n      headers: {\n        accept: \"application/vnd.github+json\",\n        authorization: `Bearer ${input.appToken}`,\n        \"content-type\": \"application/json\",\n        \"x-github-api-version\": \"2022-11-28\",\n      },\n      body: JSON.stringify({\n        url: input.webhookUrl,\n        content_type: \"json\",\n        insecure_ssl: \"0\",\n        secret: input.webhookSecret,\n      }),\n    });\n  } catch {\n    // A fetch error can embed request bodies, headers, or a proxy response.\n    // Keep it out of endpoint health, the audit log, and the board response.\n    throw new Error(\n      \"GitHub webhook configuration could not be confirmed. Reconnect to retry; repository access was not changed.\",\n    );\n  }\n  if (response.status !== 200) {\n    await response.body?.cancel().catch(() => undefined);\n    throw new Error(\n      `GitHub could not update this App's webhook (HTTP ${response.status}). Check that the App is active and reconnect.`,\n    );\n  }\n\n  // GitHub can echo a masked secret and provider error bodies are untrusted.\n  // Read a bounded response and return no provider body to callers or logs.\n  let config: Record<string, unknown>;\n  const reader = response.body?.getReader();\n  try {\n    if (!reader) throw new Error(\"Missing webhook configuration response\");\n    const chunks: Uint8Array[] = [];\n    let size = 0;","sourceCodeStart":712,"sourceCodeEnd":748,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/chat-github-webhook-config.ts#L712-L748","documentation":"Thrown by resyncGitHubAppWebhook in the Paperclip server when the PATCH/POST fetch to GitHub's webhook configuration endpoint rejects (network error, DNS failure, TLS error, etc.). The catch block deliberately swallows the underlying fetch error because fetch errors can embed request bodies, headers, or proxy responses, so the raw cause is never surfaced to endpoint health, audit logs, or the board. The safe retry path is reconnecting the GitHub connection; repository access grants are untouched.","triggerScenarios":"The fetch() call to GitHub's API for updating the GitHub App's webhook config throws: network outage, DNS failure, proxy interference, TLS handshake failure, aborted request, or an invalid webhookSecret being encoded into the request causing an undispatched request error.","commonSituations":"Corporate proxy blocking api.github.com; transient network blips during App reconnect; Docker/container networking issues; firewall egress rules dropping the outbound call; request aborted by a client disconnect mid-resync.","solutions":["Reconnect the GitHub App connection in the Paperclip board to retry the resync.","Verify outbound HTTPS access to api.github.com from the server (curl -I https://api.github.com).","Check proxy/HTTPS_PROXY environment variables and corporate firewall egress rules.","Retry after a transient network failure resolves; check server logs for the earlier fetch failures in the same window."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Before resync, confirm outbound reachability:\nconst ok = await fetch('https://api.github.com/zen', { method: 'GET' }).then(r => r.ok).catch(() => false);\nif (!ok) throw new Error('No outbound access to api.github.com; fix network before resync');","typeGuard":null,"tryCatchPattern":"try { await resyncGitHubAppWebhook(input); }\ncatch (e) {\n  if (e.message.includes('could not be confirmed')) {\n    // transient network path; schedule a retry with backoff\n    await retryWithBackoff(() => resyncGitHubAppWebhook(input), 3);\n  } else throw e;\n}","preventionTips":["Ensure stable egress to api.github.com (allowlist in firewalls/proxies).","Set and verify HTTPS_PROXY vars in containerized environments.","Monitor network health and retry resyncs automatically with backoff.","Avoid aborting in-flight resync requests (client timeouts)."],"tags":["network","github","webhook","fetch"],"backgroundTag":"network-request-failed","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}