{"record":{"id":"8b42c4d323629835","repo":"medusajs/medusa","slug":"cannot-skip-a-step-when-status-is-step-getstates","errorCode":null,"errorMessage":"Cannot skip a step when status is ${step.getStates().status}","messagePattern":"Cannot skip a step when status is (.+?)","errorType":"exception","errorClass":"MedusaError","httpStatus":null,"severity":"error","filePath":"packages/core/orchestration/src/transaction/transaction-orchestrator.ts","lineNumber":1902,"sourceCode":"      await TransactionOrchestrator.getTransactionAndStepFromIdempotencyKey(\n        responseIdempotencyKey,\n        handler,\n        transaction\n      )\n\n    if (step.getStates().status === TransactionStepStatus.WAITING) {\n      this.emit(DistributedTransactionEvent.RESUME, {\n        transaction: curTransaction,\n      })\n\n      await TransactionOrchestrator.skipStep({\n        transaction: curTransaction,\n        step,\n      })\n\n      await this.executeNext(curTransaction)\n    } else {\n      throw new MedusaError(\n        MedusaError.Types.NOT_ALLOWED,\n        `Cannot skip a step when status is ${step.getStates().status}`\n      )\n    }\n\n    return curTransaction\n  }\n\n  /**\n   * Manually force a step to retry even if it is still in awaiting status\n   * @param responseIdempotencyKey - The idempotency key for the step\n   * @param handler - The handler function to execute the step\n   * @param transaction - The current transaction. If not provided it will be loaded based on the responseIdempotencyKey\n   */\n  public async retryStep({\n    responseIdempotencyKey,\n    handler,\n    transaction,","sourceCodeStart":1884,"sourceCodeEnd":1920,"githubUrl":"https://github.com/medusajs/medusa/blob/5e06e544a296b9033f20f71f11c559f81a0e5739/packages/core/orchestration/src/transaction/transaction-orchestrator.ts#L1884-L1920","documentation":"skipTransactionStep/skipStep APIs mark a step as skipped so the flow continues without executing it. This is only legal while the step is still pending/awaiting response (e.g. WAITING_FOR_CONFIRMATION). Skipping a step that is already running, done, or failed would corrupt the flow, so MedusaError NOT_ALLOWED is thrown with the current status in the message.","triggerScenarios":"Calling skipStep on a step whose status is not in the skippable set — e.g. after it already executed, while it is currently invoking, or after the transaction finished. Common with waitFor-style steps once their status advanced.","commonSituations":"User-approval flows where the skip request races with the step auto-completing; UI allowing skip on already-processed steps; retrying a skip request that already succeeded.","solutions":["Refresh the transaction/step state immediately before skipping and only proceed if the step is still awaiting (e.g. status 'waiting_for_response' / not invoked)","Make skip endpoints idempotent: treat already-completed states as success no-op","Guard against races with a per-transaction lock"],"exampleFix":"// before\nawait orchestrator.skipStep(transactionId, action)\n\n// after\nconst [, step] = await orchestrator.getTransactionStep(transactionId, action)\nif (step.getStates().status === 'invoking' || step.getStates().status === 'done') {\n  return { skipped: false, reason: 'step already progressed' }\n}\nawait orchestrator.skipStep(transactionId, action)","handlingStrategy":"validation","validationCode":"const [, step] = await orchestrator.getTransactionStep(transactionId, action)\nconst skippable = ['waiting_for_response', 'not_started', 'queue']\nif (skippable.includes(step.getStates().status)) {\n  await orchestrator.skipStep(transactionId, action)\n} else {\n  return { skipped: false, status: step.getStates().status }\n}","typeGuard":null,"tryCatchPattern":"try { await orchestrator.skipStep(transactionId, action) } catch (e) { if (e.type === 'not_allowed' && /Cannot skip/.test(e.message)) return { skipped: false } throw e }","preventionTips":["Load fresh step state immediately before skipping","Disable skip UI for steps that already progressed"],"tags":["orchestration","workflow","skip","invalid-state"],"backgroundTag":"invalid-workflow-state-transition","analyzedSha":"5e06e544a296b9033f20f71f11c559f81a0e5739","analyzedAt":"2026-08-27T07:24:39.599Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}