{"record":{"id":"7f50a550cf087861","repo":"different-ai/openwork","slug":"automation-run-history-was-invalid","errorCode":null,"errorMessage":"Automation run history was invalid.","messagePattern":"Automation run history was invalid\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ee/apps/den-web/app/(den)/dashboard/_components/automation-data.tsx","lineNumber":37,"sourceCode":"\nexport function useAutomations() {\n  return useQuery({ queryKey: [\"automations\", \"list\"], queryFn: async () => automationListSchema.parse(await payload(\"/v1/automations?limit=100\")) });\n}\n\nexport function useAutomation(automationId: string | null) {\n  return useQuery({\n    queryKey: [\"automations\", \"detail\", automationId],\n    queryFn: async () => automationDetailSchema.parse(await payload(`/v1/automations/${encodeURIComponent(automationId ?? \"\")}`)),\n    enabled: Boolean(automationId),\n  });\n}\n\nexport function useAutomationRuns(automationId: string | null) {\n  return useQuery({\n    queryKey: [\"automations\", \"runs\", automationId],\n    queryFn: async () => {\n      const value = await payload(`/v1/automations/${encodeURIComponent(automationId ?? \"\")}/runs?limit=100`);\n      if (typeof value !== \"object\" || value === null || !(\"items\" in value) || !Array.isArray(value.items)) throw new Error(\"Automation run history was invalid.\");\n      return value.items.map((item) => automationRunSchema.parse(item));\n    },\n    enabled: Boolean(automationId),\n    refetchInterval: 5_000,\n  });\n}\n\nexport function useAutomationRun(runId: string | null) {\n  return useQuery({\n    queryKey: [\"automations\", \"run\", runId],\n    queryFn: async () => automationRunReceiptSchema.parse(await payload(`/v1/automation-runs/${encodeURIComponent(runId ?? \"\")}`)),\n    enabled: Boolean(runId),\n    refetchInterval: (query) => {\n      const status = query.state.data?.run.status;\n      return status && [\"queued\", \"claimed\", \"running\"].includes(status) ? 2_000 : false;\n    },\n  });\n}","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-web/app/(den)/dashboard/_components/automation-data.tsx#L19-L55","documentation":"useAutomationRuns fetches /v1/automations/{id}/runs via payload(), then validates that the response is an object containing an items array before parsing each item with automationRunSchema. This error is thrown when the endpoint returned 2xx but the body is not the expected {items:[...]} shape — a contract violation the client refuses to process.","triggerScenarios":"The runs endpoint returns null, a bare array instead of {items}, or an object without an items field; a paginated-envelope change from the server; a proxy returning an empty 200.","commonSituations":"Server/client version skew after the runs API changed shape; hitting an old mock server; response transformed by middleware (e.g. array unwrapping); automation deleted concurrently so the server returns an odd success body.","solutions":["Log/inspect the raw payload to see the actual shape and compare with {items:[]}.","Update the client check if the server moved to a bare-array response (Array.isArray(value) branch).","Align server and den-web versions.","If items exist but individual items fail automationRunSchema.parse, the thrown Zod error names the mismatched field — fix the schema or server payload."],"exampleFix":"// before\nif (typeof value !== \"object\" || value === null || !(\"items\" in value) || !Array.isArray(value.items)) throw new Error(\"Automation run history was invalid.\");\n// after\nconst items = Array.isArray(value) ? value : (value as { items?: unknown[] })?.items;\nif (!Array.isArray(items)) throw new Error(\"Automation run history was invalid.\");","handlingStrategy":"type-guard","validationCode":"const value = await payload(`/v1/automations/${encodeURIComponent(automationId)}/runs?limit=100`);\nif (!isRunsResponse(value)) return []; // or show error state","typeGuard":"function isRunsResponse(v: unknown): v is { items: unknown[] } {\n  return typeof v === \"object\" && v !== null && \"items\" in v && Array.isArray((v as {items:unknown}).items);\n}","tryCatchPattern":"try {\n  const runs = await queryFn();\n} catch (err) {\n  if (err instanceof Error && err.message === \"Automation run history was invalid.\") {\n    setRuns([]); // degraded mode: show empty history, log payload\n  } else throw err;\n}","preventionTips":["Validate the runs endpoint contract with a Zod schema at the boundary, not ad-hoc checks.","Add contract tests asserting {items:[...]} for the runs endpoint.","Keep automationRunSchema in sync with server run fields.","Log the offending payload when this error fires to catch envelope changes early."],"tags":["api-contract","zod","response-parsing"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}