{"record":{"id":"a9e2cc81d756fa4b","repo":"different-ai/openwork","slug":"github-install-completion-response-was-incomplete","errorCode":null,"errorMessage":"GitHub install completion response was incomplete.","messagePattern":"GitHub install completion response was incomplete\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ee/apps/den-web/app/(den)/dashboard/_components/integration-data.tsx","lineNumber":509,"sourceCode":"                  : manifestKind === \"plugin\"\n                    ? \"Claude plugin manifest detected.\"\n                    : \"Repository available to connect.\",\n                fullName,\n                hasPluginManifest: Boolean(entry.hasPluginManifest),\n                hasPlugins: Boolean(entry.hasPluginManifest),\n                id,\n                manifestKind,\n                marketplacePluginCount: typeof entry.marketplacePluginCount === \"number\" ? entry.marketplacePluginCount : null,\n                name: toRepoName(fullName),\n                private: Boolean(entry.private),\n              } satisfies IntegrationRepo];\n            })\n          : [];\n\n        const connectorAccountId = connectorAccount ? asString(connectorAccount.id) : null;\n        const connectorAccountName = connectorAccount ? asString(connectorAccount.displayName) : null;\n        if (!connectorAccount || !connectorAccountId || !connectorAccountName) {\n          throw new Error(\"GitHub install completion response was incomplete.\");\n        }\n\n        result = {\n          connectorAccount: {\n            displayName: connectorAccountName,\n            id: connectorAccountId,\n            metadata: isRecord(connectorAccount.metadata) ? connectorAccount.metadata : undefined,\n          },\n          repositories,\n        };\n      });\n      if (!result) {\n        throw new Error(\"GitHub install completion response was incomplete.\");\n      }\n      return result;\n    },\n  });\n}","sourceCodeStart":491,"sourceCodeEnd":527,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-web/app/(den)/dashboard/_components/integration-data.tsx#L491-L527","documentation":"useGithubInstallCompletion exchanges the GitHub installation callback for a connector account record. After the server responds, the payload's items are scanned for a connectorAccount; if none is found or its id/displayName fields are missing/empty, this error is thrown because the completed install cannot be mapped to a local account.","triggerScenarios":"The completion endpoint returns 200 without a connectorAccount item (installation webhook not yet processed server-side), connectorAccount lacks id or displayName, or the response schema changed.","commonSituations":"User completed GitHub install but the server-side webhook that creates the connector account has not fired yet (race condition); GitHub webhook delivery failed; API version drift.","solutions":["Wait a few seconds and retry — the connector account is often created asynchronously via webhook after the GitHub redirect.","Check the server received the GitHub installation webhook (GitHub App webhook settings / delivery logs).","Inspect the completion response body to see which of id/displayName is missing.","If persistently missing, verify the GitHub App's webhook URL and secret on the Den server."],"exampleFix":"// before\nif (!connectorAccount || !connectorAccountId || !connectorAccountName) {\n  throw new Error(\"GitHub install completion response was incomplete.\");\n}\n// after\nif (!connectorAccount || !connectorAccountId || !connectorAccountName) {\n  await new Promise((r) => setTimeout(r, 2000));\n  // refetch completion payload once before giving up\n}\nif (!connectorAccount || !connectorAccountId || !connectorAccountName) {\n  throw new Error(\"GitHub install completion response was incomplete.\");\n}","handlingStrategy":"retry","validationCode":"const body = await res.json();\nconst items = Array.isArray(body?.items) ? body.items : [];\nif (items.length === 0) {\n  // connector account may not exist yet — schedule a delayed refetch\n}","typeGuard":"function hasConnectorAccount(p: unknown): p is { items: Array<{ connectorAccount: { id: string; displayName: string } }> } {\n  if (typeof p !== \"object\" || p === null) return false;\n  const items = (p as { items?: unknown }).items;\n  if (!Array.isArray(items)) return false;\n  return items.some((i) => {\n    const ca = (i as { connectorAccount?: unknown }).connectorAccount;\n    return (\n      typeof ca === \"object\" && ca !== null &&\n      typeof (ca as { id?: unknown }).id === \"string\" &&\n      typeof (ca as { displayName?: unknown }).displayName === \"string\"\n    );\n  });\n}","tryCatchPattern":"try {\n  const completion = await completionQuery;\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"incomplete\")) {\n    await delay(2000);\n    return completionQuery.refetch(); // webhook may not have landed yet\n  }\n  throw e;\n}","preventionTips":["Retry the completion query with backoff to absorb webhook processing delay.","Ensure the GitHub App webhook URL/secret are correctly configured server-side.","Add a server test simulating install completion returning a full connector account.","Alert on installations without a connector account after N seconds."],"tags":["github-app","webhook","race-condition"],"backgroundTag":"missing-response-field","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}