medusajs/medusa · error · Error

Step registration requires id. Received

Error message

Step registration requires id. Received: ${JSON.stringify(data)}

What it means

Dev-server validation error from StepHandler.validate: a workflow-step resource was registered without an `id`. Steps are tracked in an inverse registry (which workflow uses which step file) to support hot-reload, so a missing id aborts registration.

Solutions

  1. Pass the step's unique id (the first argument given to createStep) in the registration data.
  2. If the id is computed, assert it is a non-empty string before registering.
  3. Register steps with type 'step' and include either sourcePath or workflowId alongside the id.

Example fix

// before
registerDevServerResource({ type: 'step', sourcePath, workflowId }) // no id

// after
registerDevServerResource({ type: 'step', id: 'create-order-step', sourcePath, workflowId })
Defensive patterns

Strategy: validation

Validate before calling

if (!data.id) throw new Error(`Missing step id: ${JSON.stringify(data)}`)

Type guard

function isStepResourceData(d: unknown): d is StepResourceData {
  return !!d && typeof (d as any).id === 'string' && !!(d as any).sourcePath || !!(d as any).workflowId
}

Prevention

When it happens

Trigger: Calling the step registration API with data lacking the step id — typically the step's unique name string; loaders that derive ids from step configuration and end up with undefined; registering an inline arrow-function step that was never assigned a name.

Common situations: Custom tooling or plugins that auto-register steps from files; refactoring step names while the registration path still reads the old property; creating steps with createStep dynamically where the id variable is misspelled.

Related errors


AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27). Data as JSON: /api/errors/4c7d71b803ed7328. Report an issue: GitHub.

Appendix: source

Thrown at packages/core/utils/src/dev-server/handlers/step-handler.ts:8

import { ResourceEntry, ResourceTypeHandler, StepResourceData } from "../types"

export class StepHandler implements ResourceTypeHandler<StepResourceData> {
  readonly type = "step"

  constructor(private inverseRegistry: Map<string, string[]>) {}

  validate(data: StepResourceData): void {
    if (!data.id) {
      throw new Error(
        `Step registration requires id. Received: ${JSON.stringify(data)}`
      )
    }

    if (!data.sourcePath && !data.workflowId) {
      throw new Error(
        `Step registration requires either sourcePath or workflowId. Received: ${JSON.stringify(
          data
        )}`
      )
    }
  }

  resolveSourcePath(data: StepResourceData): string {
    if (data.sourcePath) {
      return data.sourcePath

View on GitHub (pinned to 5e06e544a2)