different-ai/openwork · error
Workflow action failed (${response.status}).
Error message
Workflow action failed (${response.status}). What it means
mutationJson performs POST/PUT workflow mutations (activate/retire artifact view) via requestJson and throws 'Workflow action failed (STATUS).' when response.ok is false, preferring a server-provided error message from getErrorMessage(payload, fallback). It is the single choke point for all workflow mutation calls in this module.
Source
Thrown at ee/apps/den-web/app/(den)/dashboard/_components/workflow-detail-data.tsx:53
throw new Error("Workflow response was incomplete.");
}
return {
workflow: {
type: "workflow", id: workflow.id, plugin, name: workflow.name,
description: typeof workflow.description === "string" ? workflow.description : null,
role, state, resultState,
latestSuccessfulAt: typeof workflow.latestSuccessfulAt === "string" ? workflow.latestSuccessfulAt : null,
viewState, activeViewTitle: typeof workflow.activeViewTitle === "string" ? workflow.activeViewTitle : null,
automationCount: workflow.automationCount, source: { kind: sourceKind },
},
script: workflowDetailSchema.parse(value.script),
views: value.views.map((view) => generatedArtifactViewSchema.parse(view)),
};
}
async function mutationJson(path: string, method: "POST" | "PUT") {
const { response, payload } = await requestJson(path, { method }, 15_000);
if (!response.ok) throw new Error(getErrorMessage(payload, `Workflow action failed (${response.status}).`));
return payload;
}
export function useWorkflowLibraryDetail(workflowId: string) {
return useQuery({
queryKey: ["workflow", workflowId],
queryFn: async () => {
const { response, payload } = await requestJson(`/v1/workflows/${encodeURIComponent(workflowId)}`, { method: "GET" }, 15_000);
if (!response.ok) throw new Error(getErrorMessage(payload, `Failed to load Workflow (${response.status}).`));
return parseWorkflowDetail(payload);
},
});
}
export function useActivateArtifactView(workflowId: string) {
const client = useQueryClient();
return useMutation({
mutationFn: async ({ viewId, revisionId }: { viewId: string; revisionId: string }) => generatedArtifactViewSchema.parse(await mutationJson(View on GitHub (pinned to 2b7df46e8a)
Solutions
- Read the response.status and any message in the JSON payload to identify the exact server rejection cause.
- Re-authenticate if status is 401 (sign-in flow refreshes the Den session).
- Verify the current member's role permits activating/retiring views (owner/admin).
- Confirm the workflow and view ids still exist; refresh the detail query.
- Retry after backing off if status >= 500 or the request timed out.
Example fix
// before
const { response, payload } = await requestJson(path, { method }, 15_000);
if (!response.ok) throw new Error(getErrorMessage(payload, `Workflow action failed (${response.status}).`));
// after (caller-side retry on transient failures)
try { await mutationJson(path, "POST"); }
catch (e) { if (isTransient(e)) await retryWithBackoff(() => mutationJson(path, "POST")); else throw e; } Defensive patterns
Strategy: try-catch
Validate before calling
if (!workflowId || !viewId) throw new Error("Missing workflow/view id before mutation"); Type guard
null
Try / catch
try {
await mutationJson(`/v1/workflows/${id}/views/${viewId}`, "POST");
} catch (e) {
if (e instanceof Error && e.message.startsWith("Workflow action failed")) {
if (/\(401\)/.test(e.message)) await reauth();
else if (/\((5\d\d)\)/.test(e.message)) scheduleRetry();
else showToast(e.message);
} else throw e;
} Prevention
- Refresh sessions before long editing sessions.
- Check role/permission flags before enabling mutation buttons.
- Re-fetch detail before mutating to confirm the view still exists.
- Add backoff retry for 5xx only.
When it happens
Trigger: Any POST/PUT to a workflow view endpoint returning a non-2xx: 401 expired session, 403 insufficient role, 404 unknown workflow/view id, 409 conflicting view state, 422 invalid view payload, 5xx Den server error, or a timeout at the 15s requestJson limit.
Common situations: Session token expired mid-edit, user role downgraded below what the mutation requires, activating a view on a workflow that was concurrently retired, self-hosted Den behind a misconfigured proxy returning 502, or the 15s timeout firing on a slow network.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- Failed to load desktop policies (${response.status}).
- Could not load egress diagnostics (${response.status}).
- Egress diagnostic could not start (${response.status}).
- Failed to load inference settings (${response.status}).
- Failed to load dashboards (${response.status}).
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/87d4542af735d11e.
Report an issue: GitHub.