medusajs/medusa · error · MedusaError

invalid_data

invalid_data

Error message

Sales channels with IDs ${notFound.join(", ")} do not exist

What it means

cancel() in the Redis engine resolves the flow definition via MedusaWorkflow.getWorkflow before loading the transaction. An unregistered workflow id yields MedusaError NOT_FOUND with the id embedded in the message.

Source

Thrown at packages/core/core-flows/src/api-key/steps/validate-sales-channel-exists.ts:40

 * If the sales channel does not exist, the step throws an error.
 */
export const validateSalesChannelsExistStep = createStep(
  validateSalesChannelsExistStepId,
  async (data: ValidateSalesChannelsExistStepInput, { container }) => {
    const salesChannelModuleService =
      container.resolve<ISalesChannelModuleService>(Modules.SALES_CHANNEL)

    const salesChannels = await salesChannelModuleService.listSalesChannels(
      { id: data.sales_channel_ids },
      { select: ["id"] }
    )

    const salesChannelIds = salesChannels.map((v) => v.id)

    const notFound = arrayDifference(data.sales_channel_ids, salesChannelIds)

    if (notFound.length) {
      throw new MedusaError(
        MedusaError.Types.INVALID_DATA,
        `Sales channels with IDs ${notFound.join(", ")} do not exist`
      )
    }

    return new StepResponse(salesChannelIds)
  }
)

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Import the workflow module in the cancelling process, or route cancels through a service that has it registered
  2. Verify the id matches the createWorkflow id exactly
  3. Handle NOT_FOUND gracefully for stale cancellations

Example fix

// before
await engine.cancel(row.workflow_id, row.transaction_id)
// after
if (!MedusaWorkflow.getWorkflow(row.workflow_id)) return { alreadyGone: true }
await engine.cancel(row.workflow_id, row.transaction_id)
Defensive patterns

Strategy: type-guard

Validate before calling

if (!MedusaWorkflow.getWorkflow(workflowId)) throw new Error(`cannot cancel unregistered workflow ${workflowId}`)
await engine.cancel(workflowId, transactionId)

Type guard

const isRegistered = (id: string) => Boolean(MedusaWorkflow.getWorkflow(id))

Try / catch

catch (e) { if (e.type === 'not_found' && e.message.includes('not found')) return { status: 'unknown-workflow' }; throw e }

Prevention

When it happens

Trigger: cancel('typo-id', txId) or cancelling a workflow whose defining module is not imported in the process handling the cancel request.

Common situations: Admin/monitoring services that cancel arbitrary workflows by id read from a database but never import the workflow modules; deployments splitting the API and engine processes.

Related errors


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