{"record":{"id":"524c4489790398c5","repo":"different-ai/openwork","slug":"library-response-was-incomplete","errorCode":null,"errorMessage":"Library response was incomplete.","messagePattern":"Library response was incomplete\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ee/apps/den-web/app/(den)/dashboard/_components/library-data.tsx","lineNumber":262,"sourceCode":"    : null;\n  if (!id || (value.plugin !== null && !plugin) || !name || description === undefined || !role || !edges || !state || !resultState\n    || latestSuccessfulAt === undefined || !viewState || activeViewTitle === undefined || !source\n    || typeof value.automationCount !== \"number\" || !Number.isInteger(value.automationCount) || value.automationCount < 0) return null;\n  return { type: \"workflow\", id, plugin, name, description, role, edges, state, resultState, latestSuccessfulAt, viewState, activeViewTitle, automationCount: value.automationCount, source };\n}\n\nfunction parseLibraryItem(value: unknown): LibraryItem | null {\n  if (!isRecord(value)) return null;\n  if (value.type === \"plugin\") return parsePlugin(value);\n  if (value.type === \"app\") return null;\n  if (value.type === \"connection\") return parseConnection(value);\n  if (value.type === \"workflow\") return parseWorkflow(value);\n  return null;\n}\n\nexport function parseLibraryPayload(payload: unknown): LibraryItem[] {\n  if (!isRecord(payload) || !Array.isArray(payload.items)) {\n    throw new Error(\"Library response was incomplete.\");\n  }\n  const items = payload.items\n    .map(parseLibraryItem)\n    .filter((item): item is LibraryItem => item !== null);\n  const supportedItemCount = payload.items.filter((item) => !isRecord(item) || item.type !== \"app\").length;\n  if (items.length !== supportedItemCount) {\n    throw new Error(\"Library response was incomplete.\");\n  }\n  return items;\n}\n\nexport function useLibrary() {\n  return useQuery({\n    queryKey: libraryQueryKeys.items,\n    queryFn: async (): Promise<LibraryItem[]> => {\n      const { response, payload } = await requestJson(\n        \"/v1/me/library\",\n        { method: \"GET\" },","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-web/app/(den)/dashboard/_components/library-data.tsx#L244-L280","documentation":"parseLibraryPayload validates the payload returned from GET /v1/me/library before trusting it. If the payload is not a plain object or is missing an `items` array, the library item list is unusable, so it throws this error instead of returning silently-empty data. It is a defensive schema check on the server response.","triggerScenarios":"The /v1/me/library endpoint returns 200 but the JSON body is not an object (e.g. null, string, array) or the object lacks an `items` array property (e.g. the server returned an error-shaped body with a 200 status, a proxy stripped the body, or an API contract change renamed `items`).","commonSituations":"Server deployed an API version where the library payload shape changed; a gateway/CDN returned an HTML error page with status 200; the client hit a different (older/newer) backend than the one the frontend expects; response body intercepted/rewritten by middleware.","solutions":["Log the raw payload of the /v1/me/library response and confirm it is an object containing `items: []`.","Check the den-api route handler for /v1/me/library to ensure it returns `{ items: [...] }` on success.","Verify frontend and backend versions match (no stale deploy or mixed API versions).","Inspect for proxies/interceptors (service worker, test mocks) rewriting the response body.","Update the parsing function if the API contract intentionally changed."],"exampleFix":"// before (server returning bare list)\nreturn NextResponse.json(items);\n// after (server returning expected envelope)\nreturn NextResponse.json({ items });","handlingStrategy":"validation","validationCode":"function isLibraryPayload(p: unknown): p is { items: unknown[] } {\n  return typeof p === \"object\" && p !== null && !Array.isArray(p) && Array.isArray((p as { items?: unknown }).items);\n}\n// call: if (!isLibraryPayload(await res.json())) throw new Error(\"Library response was incomplete.\");","typeGuard":"const isRecord = (v: unknown): v is Record<string, unknown> => typeof v === \"object\" && v !== null && !Array.isArray(v);","tryCatchPattern":"try {\n  const items = await fetchLibrary();\n} catch (err) {\n  if (err instanceof Error && err.message === \"Library response was incomplete.\") {\n    console.error(\"Malformed /v1/me/library payload\", err);\n    // show empty-library fallback with a refresh action\n  } else throw err;\n}","preventionTips":["Add contract tests asserting /v1/me/library returns { items: [] } even when empty.","Keep frontend parsers and server response shapes versioned together.","Alert on 200 responses whose body fails schema validation in production telemetry.","Avoid interceptors/mocks that rewrite JSON response bodies."],"tags":["network","api-contract","schema-validation","den-web"],"backgroundTag":"api-response-schema-mismatch","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}