{"record":{"id":"808b44ff10a28bb6","repo":"medusajs/medusa","slug":"invalid-data-808b44","errorCode":"invalid_data","errorMessage":"Gift card (${giftCard.code}) has no balance","messagePattern":"Gift card \\((.+?)\\) has no balance","errorType":"validation","errorClass":"MedusaError","httpStatus":400,"severity":"error","filePath":"packages/plugins/loyalty/src/workflows/carts/steps/validate-gift-card-balances.ts","lineNumber":51,"sourceCode":" *     \"GC-XXXX\": {\n *       balance: 100,\n *       credit: 150,\n *       debit: 50,\n *     }\n *   },\n * })\n */\nexport const validateGiftCardBalancesStep = createStep(\n  \"validate-gift-card-balances\",\n  async function ({\n    giftCards,\n    giftCardsBalanceMap,\n  }: ValidateGiftCardBalancesStepInput) {\n    for (const giftCard of giftCards) {\n      const stats = giftCardsBalanceMap[giftCard.code];\n\n      if (MathBN.convert(stats.balance).lte(0)) {\n        throw new MedusaError(\n          MedusaError.Types.INVALID_DATA,\n          `Gift card (${giftCard.code}) has no balance`\n        );\n      }\n    }\n  }\n);\n","sourceCodeStart":33,"sourceCodeEnd":59,"githubUrl":"https://github.com/medusajs/medusa/blob/5e06e544a296b9033f20f71f11c559f81a0e5739/packages/plugins/loyalty/src/workflows/carts/steps/validate-gift-card-balances.ts#L33-L59","documentation":"validateGiftCardBalancesStep (used when preparing cart credit lines) throws when a gift card attached to the cart has a balance of zero or less. A gift card with no remaining balance cannot contribute to the cart total, so the flow aborts.","triggerScenarios":"Confirming/validating a cart that still references a fully-redeemed gift card; giftCardsBalanceMap stats for that code show balance <= 0.","commonSituations":"The gift card was drained by a previous completed order but remained on a draft cart, or a shared gift card was used elsewhere between add-to-cart and checkout.","solutions":["Remove the exhausted gift card from the cart before confirming","Show the customer an up-to-date gift card balance and let them pick another payment method","Re-fetch gift card stats at confirmation time and filter out zero-balance cards"],"exampleFix":"// before\nawait confirmCartCreditLinesWorkflow.run({ input: { cart_id: cart.id } })\n// after\nconst active = giftCards.filter((gc) => stats[gc.code].balance > 0)\nawait removeGiftCardFromCartWorkflow.run({ input: { cart_id: cart.id, code: drainedGc.code } })\nawait confirmCartCreditLinesWorkflow.run({ input: { cart_id: cart.id } })","handlingStrategy":"validation","validationCode":"const usable = giftCards.filter((gc) => Number(stats[gc.code]?.balance ?? 0) > 0)","typeGuard":"const hasGiftCardBalance = (gc: string) => Number(stats[gc]?.balance ?? 0) > 0","tryCatchPattern":null,"preventionTips":["Refresh gift card balances before confirmation","Remove drained cards from carts proactively"],"tags":["gift-card","balance","cart","loyalty"],"backgroundTag":"insufficient-funds","analyzedSha":"5e06e544a296b9033f20f71f11c559f81a0e5739","analyzedAt":"2026-08-27T07:24:39.599Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}