medusajs/medusa · error · Error

If a transaction is not provided, the handler is required

Error message

If a transaction is not provided, the handler is required

What it means

TransactionOrchestrator's step-response APIs (e.g. transactionStepResponse / resumeByResponseIdempotencyKey) can resolve a transaction either from a passed DistributedTransaction or by loading it via a handler using the responseIdempotencyKey. If neither is provided, it has no way to locate the transaction and throws this plain Error.

Source

Thrown at packages/core/orchestration/src/transaction/transaction-orchestrator.ts:1824

  ): TransactionStep | null {
    for (const key in flow.steps) {
      if (action === flow.steps[key]?.definition?.action) {
        return flow.steps[key]
      }
    }
    return null
  }

  private static async getTransactionAndStepFromIdempotencyKey(
    responseIdempotencyKey: string,
    handler?: TransactionStepHandler,
    transaction?: DistributedTransactionType
  ): Promise<[DistributedTransactionType, TransactionStep]> {
    const [modelId, transactionId, action, actionType] =
      responseIdempotencyKey.split(TransactionOrchestrator.SEPARATOR)

    if (!transaction && !handler) {
      throw new Error(
        "If a transaction is not provided, the handler is required"
      )
    }

    if (!transaction) {
      const existingTransaction =
        await TransactionOrchestrator.loadTransactionById(
          modelId,
          transactionId
        )

      if (existingTransaction === null) {
        throw new MedusaError(
          MedusaError.Types.NOT_FOUND,
          `Transaction ${transactionId} could not be found.`
        )
      }

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Pass the handler argument (loader) so the orchestrator can fetch the transaction by model/transaction id
  2. Or pass the DistributedTransaction instance you already hold

Example fix

// before
await orchestrator.resumeByResponseIdempotencyKey(key)

// after
await orchestrator.resumeByResponseIdempotencyKey(
  key,
  async (modelId, txId) => loadTxFromStorage(modelId, txId)
)
Defensive patterns

Strategy: validation

Validate before calling

if (!transaction && !handler) {
  throw new Error('Provide a DistributedTransaction or a loader handler')
}
await orchestrator.transactionStepResponse(key, transaction, handler)

Prevention

When it happens

Trigger: Calling a method like resumeByResponseIdempotencyKey/getTransactionStepByAction with a responseIdempotencyKey but passing neither a transaction object nor a handler (the function used to load the transaction from storage).

Common situations: Custom integrations responding to async step callbacks (e.g. webhook completing a waitFor step) where the developer only passes the idempotency key, forgetting the handler that loads persisted state.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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