twentyhq/twenty · error · Error

Couldn't create step

Error message

Couldn't create step

What it means

Thrown in useCreateStep after createWorkflowVersionStep returns: the stepsDiff contains neither a CREATE entry whose value.id matches the new step id, nor a CHANGE entry containing that id. The backend did not register the new step in the returned diff.

Source

Thrown at packages/twenty-front/src/modules/workflow/workflow-steps/hooks/useCreateStep.ts:85

          nextStepId,
          position,
          parentStepConnectionOptions: connectionOptions,
          defaultSettings,
        })
      )?.data?.createWorkflowVersionStep;

      const stepsDiff = workflowVersionStepChanges?.stepsDiff as Difference[];

      const addedStepDiff = stepsDiff?.find(
        (diff) => diff.type === 'CREATE' && diff.value.id === id,
      ) as Nullable<DifferenceCreate>;

      const createdFirstStepDiff = stepsDiff?.find(
        (diff) => diff.type === 'CHANGE' && diff.value?.[0]?.id === id,
      ) as Nullable<DifferenceChange>;

      if (!isDefined(createdFirstStepDiff) && !isDefined(addedStepDiff)) {
        throw new Error("Couldn't create step");
      }

      if (shouldSelectNode) {
        setWorkflowSelectedNode(id);
      }
      setWorkflowLastCreatedStepId(id);

      return isDefined(createdFirstStepDiff)
        ? createdFirstStepDiff.value[0]
        : addedStepDiff?.value;
    } finally {
      setIsLoading(false);
    }
  };

  return {
    createStep,
  };

View on GitHub (pinned to 1f5dd2bbd2)

Solutions

  1. Inspect the createWorkflowVersionStep GraphQL response (data + errors) in DevTools.
  2. Confirm newStepType is a valid WorkflowActionType and parentStepId/nextStepId reference existing steps.
  3. Ensure the workflow version is a DRAFT (getUpdatableWorkflowVersion resolved); if not, a draft creation may have silently failed upstream.

Example fix

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

Strategy: try-catch

Validate before calling

const isValidCreateStepInput = (
  stepType: WorkflowActionType,
  parentStepId: string | undefined,
  existingStepIds: Set<string>,
): boolean =>
  typeof stepType === 'string' && (parentStepId === undefined || existingStepIds.has(parentStepId));

Type guard

const hasCreateStepDiff = (diff: Difference[] | undefined, id: string): boolean =>
  Array.isArray(diff) && diff.some((d) => d.type === 'CREATE' && (d as any).value?.id === id);

Try / catch

try {
  await createStep({ newStepType, parentStepId, nextStepId, ... });
} catch (e) {
  showError((e as Error).message); // "Couldn't create step"
}

Prevention

When it happens

Trigger: Backend rejects the new step (invalid newStepType, parentStepId pointing to a nonexistent step, version in a non-editable state) and returns a 200 with an empty/no-op diff. The returned diff shape differs from expectations. Concurrent edit already removed the parent.

Common situations: Invalid step type. parentStepId/nextStepId stale after another edit. Workflow version locked or already published. Backend bug returning an unchanged diff on success.

Related errors


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