{"record":{"id":"0bbab25c7b000807","repo":"different-ai/openwork","slug":"github-plugin-preview-response-was-incomplete","errorCode":null,"errorMessage":"GitHub plugin preview response was incomplete.","messagePattern":"GitHub plugin preview response was incomplete\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ee/apps/den-web/app/(den)/dashboard/_components/mcp-connections-screen.tsx","lineNumber":206,"sourceCode":"\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n  return typeof value === \"object\" && value !== null;\n}\n\nfunction asString(value: unknown): string | null {\n  return typeof value === \"string\" && value.trim().length > 0 ? value.trim() : null;\n}\n\nfunction parseSkippedReason(value: unknown): GithubPluginImportSkippedReason | null {\n  if (value === \"headers_unsupported\" || value === \"invalid_config\" || value === \"invalid_url\" || value === \"local_unsupported\" || value === \"missing_url\" || value === \"unsupported_auth\") {\n    return value;\n  }\n  return null;\n}\n\nfunction parseGithubPluginImportPreview(payload: unknown): GithubPluginImportPreview {\n  const item = isRecord(payload) && isRecord(payload.item) ? payload.item : null;\n  if (!item) throw new Error(\"GitHub plugin preview response was incomplete.\");\n\n  return {\n    repositoryFullName: asString(item.repositoryFullName) ?? \"\",\n    rootPath: asString(item.rootPath) ?? \"\",\n    servers: Array.isArray(item.servers)\n      ? item.servers.flatMap((entry) => {\n          if (!isRecord(entry)) return [];\n          const name = asString(entry.name);\n          const serverKey = asString(entry.serverKey);\n          if (!name || !serverKey) return [];\n          return [{\n            name,\n            serverKey,\n            url: asString(entry.url),\n            supported: entry.supported === true,\n            skippedReason: parseSkippedReason(entry.skippedReason),\n          }];\n        })","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-web/app/(den)/dashboard/_components/mcp-connections-screen.tsx#L188-L224","documentation":"parseGithubPluginImportPreview validates the payload returned by the GitHub plugin import preview endpoint. It only accepts a JSON object containing a nested `item` object; anything else (null, array, string, or an object without `item`) triggers this error. The library throws eagerly so callers never work with a partially-shaped preview object.","triggerScenarios":"The import-preview fetch resolved with HTTP 200 but the body is not `{ item: {...} }` — e.g. the API returned `{ error: ... }`, an empty object, an HTML error page parsed as text, or a proxy stripped/reshaped the response.","commonSituations":"Backend contract drift after a den-api deploy; a gateway (nginx/Cloudflare) returning a 200 with an error page; calling the endpoint against an older server that does not return the `item` wrapper; CSRF/auth middleware returning a JSON body without `item`.","solutions":["Log the raw response body (network tab or `await response.text()`) and confirm whether `item` is present at the top level","Verify the frontend and den-api server versions match — redeploy or pull the latest server if the endpoint contract changed","Check that auth cookies/tokens are being sent so the API does not return an alternate payload shape","If behind a proxy, fix the proxy so real API JSON is passed through instead of a 200 error page"],"exampleFix":"// before\nconst preview = parseGithubPluginImportPreview(await res.json());\n// after\nconst payload: unknown = await res.json();\nif (!(isRecord(payload) && isRecord(payload.item))) {\n  console.error('unexpected preview payload', payload);\n  throw new Error('GitHub plugin preview response was incomplete.');\n}\nconst preview = parseGithubPluginImportPreview(payload);","handlingStrategy":"type-guard","validationCode":"function hasGithubPreviewItem(payload: unknown): boolean {\n  return isRecord(payload) && isRecord(payload.item);\n}\n// call before parsing: if (!hasGithubPreviewItem(payload)) { handle gracefully; }","typeGuard":"const isGithubPluginImportPreview = (p: unknown): p is { item: Record<string, unknown> } =>\n  isRecord(p) && isRecord(p.item);","tryCatchPattern":"try {\n  const preview = parseGithubPluginImportPreview(payload);\n} catch (err) {\n  showError('Could not load the GitHub plugin preview. Verify the repository and try again.');\n  console.warn('preview payload rejected', payload);\n}","preventionTips":["Always guard the raw fetch result with isRecord checks before handing it to the parser","Log unexpected payloads to catch server contract drift early","Add a contract test asserting the preview endpoint returns { item: {...} }","Keep web app and den-api deployed in lockstep"],"tags":["schema-validation","api-response","github-plugin","den-web"],"backgroundTag":"schema-validation-failed","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}