twentyhq/twenty · error · Error

Couldn't duplicate step

Error message

Couldn't duplicate step

What it means

Thrown in useDuplicateStep after duplicateWorkflowVersionStep returns: the stepsDiff has no entry with type 'CREATE'. The backend did not produce a new step in the diff, so the duplication effectively did not happen client-side.

Source

Thrown at packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useDuplicateStep.ts:44

    }

    setIsLoading(true);

    try {
      const workflowVersionId = await getUpdatableWorkflowVersion();

      const workflowVersionStepChanges = (
        await duplicateWorkflowVersionStep({
          workflowVersionId,
          stepId,
        })
      )?.data?.duplicateWorkflowVersionStep;

      const stepsDiff = workflowVersionStepChanges?.stepsDiff as Difference[];
      const createdStepDiff = stepsDiff?.find((diff) => diff.type === 'CREATE');

      if (!isDefined(createdStepDiff)) {
        throw new Error("Couldn't duplicate step");
      }

      setWorkflowSelectedNode(createdStepDiff.value.id);
      setWorkflowLastCreatedStepId(createdStepDiff.value.id);

      return createdStepDiff.value;
    } finally {
      setIsLoading(false);
    }
  };

  return {
    duplicateStep,
  };
};

View on GitHub (pinned to 1f5dd2bbd2)

Solutions

  1. Inspect the duplicateWorkflowVersionStep response (data + errors).
  2. Verify stepId still exists in the current workflow graph at call time.
  3. Confirm the workflow version is editable (DRAFT).

Example fix

// before: if (!isDefined(createdStepDiff)) { throw new Error("Couldn't duplicate step"); }
// after:  if (!isDefined(createdStepDiff)) {
//           throw new Error(workflowVersionStepChanges?.errors?.[0]?.message ?? "Couldn't duplicate step");
//         }
Defensive patterns

Strategy: try-catch

Validate before calling

const canDuplicateStep = (stepId: string, knownStepIds: Set<string>): boolean =>
  knownStepIds.has(stepId);

Type guard

const hasDuplicateCreateDiff = (diff: Difference[] | undefined): boolean =>
  Array.isArray(diff) && diff.some((d) => d.type === 'CREATE');

Try / catch

try {
  await duplicateStep({ stepId });
} catch (e) {
  showError((e as Error).message); // "Couldn't duplicate step"
}

Prevention

When it happens

Trigger: stepId no longer exists (deleted before duplicate completed). Backend validation failure (permission, version not editable) returning a 200 with no-op diff. Diff shape change. Concurrent edit collapsed the source step.

Common situations: User double-clicks duplicate while the step is being removed. Permissions disallow step creation. Version was published between the open and the duplicate action.

Related errors


AI-assisted analysis of twentyhq/twenty@1f5dd2bbd2 (2026-08-12). Data as JSON: /api/errors/1877d05380168acf. Report an issue: GitHub.