different-ai/openwork · error

The Workflow response was invalid.

Error message

The Workflow response was invalid.

What it means

useWorkflowDetail fetches /v1/workflows/{id}?maxAgeMs=... and validates that the payload is an object containing a 'script' key before parsing it with workflowDetailSchema. If the payload is not an object, is null, or lacks 'script', it throws 'The Workflow response was invalid.' This catches shape regressions even on 2xx responses.

Source

Thrown at ee/apps/den-web/app/(den)/dashboard/_components/workflow-data.tsx:42

  snapshots: (id: string) => ["workflow", id, "snapshots"] as const,
};

async function checkedRequest(path: string, init: RequestInit, fallback: string) {
  const { response, payload } = await requestJson(path, init, 170_000);
  if (!response.ok) throw new Error(getErrorMessage(payload, `${fallback} (${response.status}).`));
  return payload;
}

export function useWorkflowDetail(configObjectId: string, maxAgeMs: number) {
  return useQuery({
    queryKey: keys.detail(configObjectId, maxAgeMs),
    queryFn: async () => {
      const payload = await checkedRequest(
      `/v1/workflows/${encodeURIComponent(configObjectId)}?maxAgeMs=${maxAgeMs}`,
      { method: "GET" },
      "Failed to load Workflow",
      );
      if (typeof payload !== "object" || payload === null || !("script" in payload)) throw new Error("The Workflow response was invalid.");
      return workflowDetailSchema.parse(payload.script);
    },
    enabled: Boolean(configObjectId),
  });
}

export function useWorkflowSnapshots(configObjectId: string) {
  return useQuery({
    queryKey: keys.snapshots(configObjectId),
    queryFn: async () => {
      const payload = await checkedRequest(
        `/v1/workflows/${encodeURIComponent(configObjectId)}/snapshots?limit=100`,
        { method: "GET" },
        "Failed to load snapshots",
      );
      if (typeof payload !== "object" || payload === null || !("items" in payload) || !Array.isArray(payload.items)) {
        throw new Error("The snapshot response was invalid.");
      }

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Inspect the raw payload and confirm whether 'script' is absent or the whole body is wrong.
  2. Align API and client versions so detail responses include script.
  3. Handle the Zod error case separately: if parse fails after 'script' exists, the script content is malformed — check server serialization.
  4. Refresh the query (bump maxAgeMs or invalidate) to bypass a stale cache.

Example fix

// before
if (typeof payload !== "object" || payload === null || !("script" in payload)) throw new Error("The Workflow response was invalid.");
return workflowDetailSchema.parse(payload.script);
// after
if (typeof payload !== "object" || payload === null || !("script" in payload)) {
  console.error("workflow detail payload:", payload);
  throw new Error("The Workflow response was invalid.");
}
return workflowDetailSchema.parse(payload.script);
Defensive patterns

Strategy: validation

Validate before calling

function hasScript(v: unknown): v is { script: unknown } {
  return isRecord(v) && "script" in v;
}

Type guard

function isWorkflowDetailPayload(v: unknown): v is { script: Record<string, unknown> } {
  return isRecord(v) && isRecord(v.script);
}

Try / catch

try {
  const detail = await detailQuery.refetch();
} catch (e) {
  if (e instanceof Error && e.message === "The Workflow response was invalid.") {
    // bypass cache: bump maxAgeMs / invalidate key, then retry once
  } else if (e instanceof ZodError) {
    // script present but malformed: report schema mismatch
  } else throw e;
}

Prevention

When it happens

Trigger: GET workflow detail returns ok but body is not an object (string/array/null), or has no 'script' property — e.g. API version without the script field, empty cached body, or maxAgeMs cache returning a placeholder.

Common situations: Server/client version mismatch after a deploy; proxy or service worker serving a cached empty body; workflow exists but was stored without a script (legacy record); subsequent workflowDetailSchema.parse throws a ZodError if script exists but is malformed.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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