different-ai/openwork · error

Failed to add Workflow (${response.status}).

Error message

Failed to add Workflow (${response.status}).

What it means

Thrown by useAttachWorkflowToPlugin in plugin-data.tsx when POSTing a workflow membership to the plugin returns a non-ok response. The body includes configObjectId and membershipSource 'manual'; getRequestError decorates the throw with server payload and status. Indicates the Den API refused to attach the workflow.

Source

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

}

export function useAttachWorkflowToPlugin(pluginId: string) {
  const queryClient = useQueryClient();
  const { runReauthableAction } = useOrgDashboard();

  return useMutation({
    mutationFn: async (workflowId: string) => {
      await runReauthableAction("attach-workflow-to-plugin", async () => {
        const { response, payload } = await requestJson(
          `/v1/plugins/${encodeURIComponent(pluginId)}/config-objects`,
          {
            method: "POST",
            body: JSON.stringify({ configObjectId: workflowId, membershipSource: "manual" }),
          },
          15000,
        );
        if (!response.ok) {
          throw getRequestError(payload, response, `Failed to add Workflow (${response.status}).`);
        }
      });
      return workflowId;
    },
    onSuccess: async () => {
      await Promise.all([
        queryClient.invalidateQueries({ queryKey: pluginQueryKeys.detail(pluginId) }),
        queryClient.invalidateQueries({ queryKey: pluginQueryKeys.list() }),
        queryClient.invalidateQueries({ queryKey: ["me", "library"] }),
      ]);
    },
  });
}

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Read the status: 409 -> the workflow is already attached, no action needed; 404 -> refresh workflow list; 403 -> check org role.
  2. Refresh plugin detail and workflow lists to clear stale ids, then retry.
  3. Validate the workflowId belongs to the same org before attaching.
  4. For 5xx, retry once after server health check.

Example fix

// before
await attachWorkflow(pluginId, workflowId);
// after: skip if already attached
const attached = pluginWorkflowIds.includes(workflowId);
if (!attached) await attachWorkflow(pluginId, workflowId);
Defensive patterns

Strategy: validation

Validate before calling

const alreadyAttached = plugin.detail?.workflowIds?.includes(workflowId);
if (alreadyAttached) return; // nothing to do, avoids 409
if (!workflowId) throw new Error('Select a workflow before attaching.');

Type guard

function isWorkflowId(v: unknown): v is string {
  return typeof v === 'string' && v.length > 0;
}

Try / catch

try {
  await attachWorkflow(pluginId, workflowId);
} catch (e) {
  const msg = e instanceof Error ? e.message : String(e);
  if (msg.includes('409')) toast('This workflow is already attached.');
  else if (msg.includes('404')) { await refreshWorkflows(); toast('Workflow no longer exists.'); }
  else toast(msg);
}

Prevention

When it happens

Trigger: POST to the plugin's workflows endpoint with { configObjectId, membershipSource: 'manual' } returns 4xx/5xx: workflow id already attached (409), workflow deleted (404), permission denied (403), or invalid configObjectId format (400).

Common situations: Two tabs attaching the same workflow concurrently; attaching a workflow that another admin removed moments ago; selecting a workflow from a different org due to stale cache.

Related errors


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