medusajs/medusa · error · Error

step workflow not found: ${data.workflowId} for step ${data.

Error message

step workflow not found: ${data.workflowId} for step ${data.id}

What it means

Dev-server error from StepHandler.resolveSourcePath: the step registered with only a workflowId, and the inverse registry has no entry for `workflow:<workflowId>` — meaning that workflow has not been registered with the dev server (or was registered under a different id). Without it the step's source file cannot be located for hot-reload.

Source

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

    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
    }

    // Look up workflow's source path
    const workflowKey = `workflow:${data.workflowId}`
    const workflowSourcePaths = this.inverseRegistry.get(workflowKey)

    if (!workflowSourcePaths || workflowSourcePaths.length === 0) {
      throw new Error(
        `step workflow not found: ${data.workflowId} for step ${data.id}`
      )
    }

    return workflowSourcePaths[0]
  }

  createEntry(data: StepResourceData): ResourceEntry {
    return {
      id: data.id,
      workflowId: data.workflowId,
    }
  }

  getInverseKey(data: StepResourceData): string {
    return `${this.type}:${data.id}`

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Register the workflow resource (type 'workflow' with matching id and its sourcePath) before registering its steps.
  2. Verify the workflowId string exactly matches the workflow's registered id.
  3. Alternatively, register the step with its own sourcePath to avoid depending on workflow registration order.

Example fix

// before
registerDevServerResource({ type: 'step', id: 's1', workflowId: 'cart-workflow' })
// 'cart-workflow' never registered

// after
registerDevServerResource({ type: 'workflow', id: 'cart-workflow', sourcePath: wfPath })
registerDevServerResource({ type: 'step', id: 's1', workflowId: 'cart-workflow' })
Defensive patterns

Strategy: validation

Validate before calling

if (!data.sourcePath) {
  const wf = inverseRegistry.get(`workflow:${data.workflowId}`)
  if (!wf?.length) throw new Error(`Register workflow ${data.workflowId} before its steps`)
}

Prevention

When it happens

Trigger: Registering a step with workflowId: 'my-workflow' before (or without ever) registering a workflow resource whose id is 'my-workflow'; using the workflow's function name instead of its registered id string.

Common situations: Ordering issues in custom loaders where steps load before workflows; renaming a workflow without updating the workflowId referenced by step registrations; registering only part of a project's resources during incremental setup.

Related errors


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