{"record":{"id":"0c795a50fc562e5c","repo":"different-ai/openwork","slug":"provider-details-were-missing-from-the-response","errorCode":null,"errorMessage":"Provider details were missing from the response.","messagePattern":"Provider details were missing from the response\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ee/apps/den-web/app/(den)/dashboard/_components/llm-provider-data.tsx","lineNumber":488,"sourceCode":"\n  return isRecord(payload) && Array.isArray(payload.providers)\n    ? payload.providers.map(asCatalogProviderSummary).filter((entry): entry is DenModelsDevProviderSummary => entry !== null)\n    : [];\n}\n\nexport async function requestLlmProviderCatalogDetail(orgId: string, providerId: string) {\n  const { response, payload } = await requestJson(\n    `/v1/llm-provider-catalog/${encodeURIComponent(providerId)}`,\n    { method: \"GET\" },\n    20000,\n  );\n\n  if (!response.ok) {\n    throw new Error(getErrorMessage(payload, `Failed to load provider details (${response.status}).`));\n  }\n\n  if (!isRecord(payload) || !payload.provider) {\n    throw new Error(\"Provider details were missing from the response.\");\n  }\n\n  const detail = asCatalogProviderDetail(payload.provider);\n  if (!detail) {\n    throw new Error(\"Provider details could not be parsed.\");\n  }\n\n  return detail;\n}\n\nexport function useOrgLlmProviders(\n  orgId: string | null,\n  options: { scope?: \"usable\" | \"manageable\" } = {},\n) {\n  const [llmProviders, setLlmProviders] = useState<DenLlmProvider[]>([]);\n  const [busy, setBusy] = useState(false);\n  const [error, setError] = useState<string | null>(null);\n  const scope = options.scope ?? \"manageable\";","sourceCodeStart":470,"sourceCodeEnd":506,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-web/app/(den)/dashboard/_components/llm-provider-data.tsx#L470-L506","documentation":"When the provider-detail endpoint responds 2xx, the payload must be an object containing a truthy `provider` field. If the body is not a record or lacks `provider`, this error is thrown instead of returning undefined downstream.","triggerScenarios":"GET /v1/llm-provider-catalog/:providerId returns 200 with a body that is not an object (null, array, string) or lacks the `provider` key — e.g. an empty 200 from a proxy, or a server contract change wrapping the detail differently.","commonSituations":"Version skew between den-web and den-api after renaming/moving the `provider` field; caching layers returning empty 200s; test doubles returning incomplete bodies.","solutions":["Log the raw payload and confirm the server is expected to return `{ provider: {...} }`.","Update the client parser if the server renamed the field.","Fix the server handler to always include `provider` in successful responses.","Bypass/clear intermediary caches to rule out empty cached 200s."],"exampleFix":"// before (server detail handler)\nreturn NextResponse.json(detail);\n// after\nreturn NextResponse.json({ provider: detail });","handlingStrategy":"type-guard","validationCode":"function hasProviderField(p: unknown): boolean {\n  return typeof p === \"object\" && p !== null && \"provider\" in p;\n}\n// check on the parsed JSON before calling the request helper's downstream logic","typeGuard":"const isRecord = (v: unknown): v is Record<string, unknown> => typeof v === \"object\" && v !== null && !Array.isArray(v);\nfunction hasProvider(v: unknown): v is { provider: Record<string, unknown> } {\n  return isRecord(v) && isRecord(v.provider);\n}","tryCatchPattern":"try {\n  const detail = await requestLlmProviderCatalogDetail(providerId);\n} catch (err) {\n  if (err instanceof Error && err.message === \"Provider details were missing from the response.\") {\n    console.error(\"Detail endpoint returned 200 without provider — check API contract\");\n  } else throw err;\n}","preventionTips":["Lock the response envelope ({ provider }) with a shared schema test.","Return non-ok (e.g. 404) instead of empty 200s when the provider is missing.","Clear CDN/proxy caches after API shape changes.","Version the detail route if the envelope must change."],"tags":["schema-validation","api-contract","llm-provider-catalog","den-web"],"backgroundTag":"missing-response-field","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}