{"record":{"id":"ebc6e0299bcfd6e9","repo":"sickn33/agentic-awesome-skills","slug":"order-is-cancelled","errorCode":null,"errorMessage":"Order is cancelled","messagePattern":"Order is cancelled","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"skills/fp-refactor/SKILL.md","lineNumber":1156,"sourceCode":"      if (!response.ok) {\n        throw new Error(`HTTP ${response.status}`);\n      }\n      return response.json();\n    })\n    .then((data) => validateUserData(data))\n    .then((validData) => enrichUserProfile(validData))\n    .catch((error) => {\n      console.error('Failed to fetch user data:', error);\n      throw error;\n    });\n}\n\n// Chained promises with conditionals\nfunction processOrder(orderId: string): Promise<OrderResult> {\n  return getOrder(orderId)\n    .then((order) => {\n      if (order.status === 'cancelled') {\n        throw new Error('Order is cancelled');\n      }\n      return order;\n    })\n    .then((order) => validateInventory(order))\n    .then((validOrder) => processPayment(validOrder))\n    .then((paidOrder) => shipOrder(paidOrder))\n    .catch((error) => {\n      logError(error);\n      return { success: false, error: error.message };\n    });\n}\n```\n\n#### After (fp-ts TaskEither)\n\n```typescript\nimport * as TE from 'fp-ts/TaskEither';\nimport * as E from 'fp-ts/Either';","sourceCodeStart":1138,"sourceCodeEnd":1174,"githubUrl":"https://github.com/sickn33/agentic-awesome-skills/blob/58d857988fcfac6986206bca2b2fe223aa437e4b/skills/fp-refactor/SKILL.md#L1138-L1174","documentation":"A business-rule throw inside fp-refactor's promise-chain processOrder: getOrder resolved successfully but its status is 'cancelled', so the pipeline aborts before inventory validation and payment. It shows conditionals-as-throws in promise chains.","triggerScenarios":"Calling processOrder on an order whose status field equals 'cancelled' — user cancelled after checkout, or a duplicate submission reusing a cancelled order's id.","commonSituations":"Double-submitted checkout forms reusing cancelled orders; delayed fulfilment jobs picking up orders cancelled in between; status strings drifting between 'cancelled' and 'canceled'.","solutions":["Guard before calling: check order.status in the UI/service layer and block submission for cancelled orders","Model status as a discriminated union so non-processable states fail to type-check","Return E.left('Order is cancelled') (or a tagged OrderCancelled error) instead of throwing"],"exampleFix":"// before\nif (order.status === 'cancelled') throw new Error('Order is cancelled')\n\n// after: tagged, typed failure\nif (order.status === 'cancelled')\n  return E.left({ _tag: 'OrderCancelled', orderId: order.id })\nreturn E.right(order)","handlingStrategy":"validation","validationCode":"const isProcessable = (o: Order) => o.status !== 'cancelled' && o.status !== 'refunded'","typeGuard":"const isActiveOrder = (o: Order): o is Order & { status: 'active' } =>\n  o.status === 'active'","tryCatchPattern":"processOrder(orderId).catch((e) => {\n  if (e instanceof Error && e.message === 'Order is cancelled') {\n    // inform user; do not retry\n    return\n  }\n  throw e\n})","preventionTips":["Check order status before submitting payment flows","Model status as a discriminated union to make invalid states unrepresentable"],"tags":["business-rule","order-processing","state-machine","promise-chain"],"backgroundTag":"invalid-order-state","analyzedSha":"58d857988fcfac6986206bca2b2fe223aa437e4b","analyzedAt":"2026-08-26T11:55:59.350Z","schemaVersion":2},"datasetVersion":"2026-08-26T14:46:13.012Z"}