different-ai/openwork · error

Provider details were missing from the response.

Error message

Provider details were missing from the response.

What it means

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.

Source

Thrown at ee/apps/den-web/app/(den)/dashboard/_components/llm-provider-data.tsx:488

  return isRecord(payload) && Array.isArray(payload.providers)
    ? payload.providers.map(asCatalogProviderSummary).filter((entry): entry is DenModelsDevProviderSummary => entry !== null)
    : [];
}

export async function requestLlmProviderCatalogDetail(orgId: string, providerId: string) {
  const { response, payload } = await requestJson(
    `/v1/llm-provider-catalog/${encodeURIComponent(providerId)}`,
    { method: "GET" },
    20000,
  );

  if (!response.ok) {
    throw new Error(getErrorMessage(payload, `Failed to load provider details (${response.status}).`));
  }

  if (!isRecord(payload) || !payload.provider) {
    throw new Error("Provider details were missing from the response.");
  }

  const detail = asCatalogProviderDetail(payload.provider);
  if (!detail) {
    throw new Error("Provider details could not be parsed.");
  }

  return detail;
}

export function useOrgLlmProviders(
  orgId: string | null,
  options: { scope?: "usable" | "manageable" } = {},
) {
  const [llmProviders, setLlmProviders] = useState<DenLlmProvider[]>([]);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const scope = options.scope ?? "manageable";

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Log the raw payload and confirm the server is expected to return `{ provider: {...} }`.
  2. Update the client parser if the server renamed the field.
  3. Fix the server handler to always include `provider` in successful responses.
  4. Bypass/clear intermediary caches to rule out empty cached 200s.

Example fix

// before (server detail handler)
return NextResponse.json(detail);
// after
return NextResponse.json({ provider: detail });
Defensive patterns

Strategy: type-guard

Validate before calling

function hasProviderField(p: unknown): boolean {
  return typeof p === "object" && p !== null && "provider" in p;
}
// check on the parsed JSON before calling the request helper's downstream logic

Type guard

const isRecord = (v: unknown): v is Record<string, unknown> => typeof v === "object" && v !== null && !Array.isArray(v);
function hasProvider(v: unknown): v is { provider: Record<string, unknown> } {
  return isRecord(v) && isRecord(v.provider);
}

Try / catch

try {
  const detail = await requestLlmProviderCatalogDetail(providerId);
} catch (err) {
  if (err instanceof Error && err.message === "Provider details were missing from the response.") {
    console.error("Detail endpoint returned 200 without provider — check API contract");
  } else throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: Version skew between den-web and den-api after renaming/moving the `provider` field; caching layers returning empty 200s; test doubles returning incomplete bodies.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/0c795a50fc562e5c. Report an issue: GitHub.