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.

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.

Appendix: 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)