medusajs/medusa · error · Error
Step registration requires either sourcePath or workflowId.
Error message
Step registration requires either sourcePath or workflowId. Received: ${JSON.stringify(data)} What it means
Dev-server validation error from StepHandler.validate: a step resource was registered with neither `sourcePath` nor `workflowId`. The dev server resolves a step's file either directly from its source path or by looking up the parent workflow's registered source; if both are absent it cannot map the step to a file, so registration is rejected.
Source
Thrown at packages/core/utils/src/dev-server/handlers/step-handler.ts:14
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
}
// Look up workflow's source path
const workflowKey = `workflow:${data.workflowId}`
const workflowSourcePaths = this.inverseRegistry.get(workflowKey)
View on GitHub (pinned to 5e06e544a2)
Solutions
- Provide sourcePath (file path of the step module) — the direct option.
- Or provide workflowId of an already-registered workflow so the handler can resolve the step's path from the inverse registry.
- If the step belongs to a workflow, make sure the workflow itself is registered before the step.
Example fix
// before
registerDevServerResource({ type: 'step', id: 'price-step' })
// after
registerDevServerResource({
type: 'step',
id: 'price-step',
sourcePath: fileURLToPath(import.meta.url),
}) Defensive patterns
Strategy: validation
Validate before calling
if (!data.sourcePath && !data.workflowId) throw new Error(`Step ${data.id} needs sourcePath or workflowId`) Type guard
function isResolvableStep(d: { sourcePath?: string; workflowId?: string }): boolean {
return Boolean(d.sourcePath) || Boolean(d.workflowId)
} Prevention
- Prefer registering steps with an explicit sourcePath for independence.
- When relying on workflowId, ensure the workflow registration happens first.
- Build registration data next to the step definition so paths are always in scope.
When it happens
Trigger: Registering a step with only { type: 'step', id } and nothing else; registration data built from a partial object where both fields were dropped during refactoring.
Common situations: Custom loaders registering steps they discovered without file context; splitting step definitions into helpers imported by workflows so the loader loses track of both the file and the owning workflow.
Related errors
- Step registration requires id. Received: ${JSON.stringify(da
- Workflow registration requires sourcePath. Received: ${JSON.
- Job registration requires sourcePath. Received: ${JSON.strin
- Subscriber registration requires sourcePath. Received: ${JSO
- Workflow registration requires id. Received: ${JSON.stringif
AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27).
Data as JSON: /api/errors/4ceba1d304f3aa6e.
Report an issue: GitHub.