{"record":{"id":"7463b3c1e1b500b4","repo":"windmill-labs/windmill","slug":"failed-to-complete-github-app-installation","errorCode":null,"errorMessage":"Failed to complete GitHub app installation","messagePattern":"Failed to complete GitHub app installation","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/routes/gh_success/+page.svelte","lineNumber":66,"sourceCode":"\t\t\terrorMessage = 'Missing or invalid required parameters'\n\t\t\tsendUserToast('Missing or invalid required parameters in the URL', true)\n\t\t\treturn\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch(`/api/w/${workspace_id}/github_app/ghes_installation_callback`, {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application/json'\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tinstallation_id\n\t\t\t\t})\n\t\t\t})\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst errorData = await response.text()\n\t\t\t\tthrow new Error(errorData || 'Failed to complete GitHub app installation')\n\t\t\t}\n\n\t\t\tisSuccess = true\n\t\t\tsendUserToast('GitHub app installed successfully', false)\n\t\t} catch (error) {\n\t\t\tconsole.error('Error during GitHub app installation:', error)\n\t\t\terrorMessage = error instanceof Error ? error.message : 'Unknown error occurred'\n\t\t\tsendUserToast(`Error installing GitHub app: ${errorMessage}`, true)\n\t\t} finally {\n\t\t\tisLoading = false\n\t\t}\n\t}\n\n\tasync function handleManagedFlow(url: URL) {\n\t\tconst workspace_id = url.searchParams.get('workspace_id') || ''\n\t\tconst installation_id_str = url.searchParams.get('installation_id') || ''\n\t\tconst account_id = url.searchParams.get('account_id') || ''\n\t\tconst jwt_token = url.searchParams.get('jwt_token') || ''","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/routes/gh_success/+page.svelte#L48-L84","documentation":"After GitHub redirects back to /gh_success, handleGhesFlow POSTs the installation data to the backend to complete a GitHub App installation (GHES flow). If the response is not ok, the page throws with the backend's error text, falling back to this fixed message, and shows a failure toast instead of the success screen.","triggerScenarios":"Completing a GitHub App installation where the completion endpoint returns 4xx/5xx: bad or expired installation_id/code from the redirect, workspace permission missing, misconfigured GHES URL, or backend error exchanging the installation.","commonSituations":"GitHub App not granted access to the target workspace; installation cancelled mid-flow leaving an invalid installation_id; wrong GHES base URL configured on the instance; backend GitHub credentials (app id/private key) misconfigured; expired one-time code after a slow redirect.","solutions":["Retry the GitHub App installation from the integration settings page to get a fresh installation_id","Verify the backend's GitHub App credentials (app ID, private key, webhook secret) and GHES URL are correct","Check backend logs for the completion endpoint's error body — it is surfaced in the thrown message","Ensure the installing user has admin rights on the workspace being linked"],"exampleFix":"// before\nthrow new Error(errorData || 'Failed to complete GitHub app installation')\n// after\nthrow new Error(errorData || `Failed to complete GitHub app installation (HTTP ${response.status})`)","handlingStrategy":"try-catch","validationCode":"// before POSTing, check the redirect payload is present\nconst params = new URLSearchParams(window.location.search)\nif (!params.get('installation_id')) {\n  sendUserToast('Missing installation_id in GitHub redirect — reinstall the app', true)\n  return\n}","typeGuard":null,"tryCatchPattern":"try {\n  await handleGhesFlow()\n} catch (e) {\n  console.error(e)\n  sendUserToast(e.message.includes('installation') && e.message !== 'Failed to complete GitHub app installation'\n    ? e.message\n    : 'GitHub app installation failed — check backend GitHub App settings and retry', true)\n}","preventionTips":["Verify the GitHub App's callback URL points at this instance's /gh_success route","Keep backend GitHub App credentials (private key, app ID, GHES URL) in sync with the app registration","Surface the backend error body in the toast for diagnosability","Handle expired codes: redirect the user to restart installation rather than retrying the same callback"],"tags":["github","oauth","integration","http"],"backgroundTag":"oauth-callback-failed","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}