twentyhq/twenty · error · Error

Malformed workflow version: missing steps information; be su

Error message

Malformed workflow version: missing steps information; be sure to create at least one step before trying to edit one

What it means

getStepDefinitionOrThrow throws when the requested stepId is not the trigger step and the workflow version's `steps` array is null/undefined. It means the loaded WorkflowVersion has no action steps at all, so any non-trigger lookup is invalid.

Source

Thrown at packages/twenty-front/src/modules/workflow/utils/getStepDefinitionOrThrow.ts:33

  trigger: WorkflowTrigger | null;
  steps: Array<WorkflowAction> | null;
}) => {
  if (stepId === TRIGGER_STEP_ID) {
    if (!isDefined(trigger)) {
      return {
        type: 'trigger',
        definition: undefined,
      } as const;
    }

    return {
      type: 'trigger',
      definition: trigger,
    } as const;
  }

  if (!isDefined(steps)) {
    throw new Error(
      'Malformed workflow version: missing steps information; be sure to create at least one step before trying to edit one',
    );
  }

  const selectedNodePosition = findStepPosition({
    steps,
    stepId,
  });
  if (!isDefined(selectedNodePosition)) {
    return undefined;
  }

  return {
    type: 'action',
    definition: selectedNodePosition.steps[selectedNodePosition.index],
  } as const;
};

View on GitHub (pinned to 1f5dd2bbd2)

Solutions

  1. Guard the call site: skip the lookup until steps is a non-null array.
  2. Ensure at least one action step exists before opening the step editor.
  3. Verify the workflow version query selects the steps field.

Example fix

// before: const def = getStepDefinitionOrThrow({ stepId, trigger, steps });
// after:  if (stepId !== TRIGGER_STEP_ID && !steps?.length) return undefined;
//         const def = getStepDefinitionOrThrow({ stepId, trigger, steps });
Defensive patterns

Strategy: type-guard

Validate before calling

const canLookupStep = (stepId: string, steps: Array<WorkflowAction> | null): boolean =>
  stepId === TRIGGER_STEP_ID || (Array.isArray(steps) && steps.length > 0);

Type guard

const hasActionSteps = (steps: Array<WorkflowAction> | null | undefined): steps is Array<WorkflowAction> =>
  Array.isArray(steps) && steps.length > 0;

Try / catch

try {
  return getStepDefinitionOrThrow({ stepId, trigger, steps });
} catch (e) {
  if (/missing steps information/.test((e as Error).message)) return undefined;
  throw e;
}

Prevention

When it happens

Trigger: Editing/selecting an action step on a workflow version that only has a trigger (steps === null). The version was created as a stub before any actions were added. Race where the version fetch has not yet populated steps.

Common situations: Newly created workflow with only a trigger. Backend returned a version shape without steps. Frontend attempted to look up a step before the workflow graph finished loading.

Understand the failure class

Related errors


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