{"record":{"id":"673370eff5d5622d","repo":"sickn33/agentic-awesome-skills","slug":"no-order","errorCode":null,"errorMessage":"No order","messagePattern":"No order","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"skills/fp-async/SKILL.md","lineNumber":931,"sourceCode":"// AFTER\nconst getUser = (id: string) =>\n  TE.tryCatch(\n    async () => {\n      const res = await fetch(`/api/users/${id}`)\n      if (!res.ok) throw new Error('Not found')\n      return res.json()\n    },\n    E.toError\n  )\n```\n\n### Chained Operations\n\n```typescript\n// BEFORE\nasync function processOrder(orderId: string) {\n  const order = await fetchOrder(orderId)\n  if (!order) throw new Error('No order')\n  const user = await fetchUser(order.userId)\n  if (!user) throw new Error('No user')\n  const result = await chargePayment(user, order.total)\n  return result\n}\n\n// AFTER\nconst processOrder = (orderId: string) =>\n  pipe(\n    TE.Do,\n    TE.bind('order', () => fetchOrder(orderId)),\n    TE.bind('user', ({ order }) => fetchUser(order.userId)),\n    TE.chain(({ user, order }) => chargePayment(user, order.total))\n  )\n```\n\n### Error Recovery\n","sourceCodeStart":913,"sourceCodeEnd":949,"githubUrl":"https://github.com/sickn33/agentic-awesome-skills/blob/58d857988fcfac6986206bca2b2fe223aa437e4b/skills/fp-async/SKILL.md#L913-L949","documentation":"Illustrative guard from the 'Chained Operations' BEFORE example: fetchOrder returned falsy, so the imperative chain aborts with 'No order'. The snippet's flat await + if-throw ladder is presented as the baseline the skill replaces with a composed TaskEither pipeline.","triggerScenarios":"processOrder invoked with an orderId that does not exist, was deleted, or whose fetch failed softly (returned undefined); also fires when fetchOrder's API returns 404 mapped to null.","commonSituations":"Client sends stale or malformed ids; retry logic reusing an id after deletion; API layer normalizing errors to null and thereby erasing the failure reason.","solutions":["Validate orderId (format/existence) before starting the chain","Make fetchOrder distinguish missing (null) from failed (throw) instead of collapsing both","Replace the if-throw ladder with pipe + TE.chain so each step's failure is a typed Left","Return discriminated errors ({ kind: 'NoOrder' } etc.) so callers branch on cause"],"exampleFix":"// before\nconst order = await fetchOrder(orderId)\nif (!order) throw new Error('No order')\n// after\npipe(\n  fetchOrderTask(orderId),\n  TE.chain(order => order == null\n    ? TE.left(new Error('No order'))\n    : TE.right(order)),\n  TE.chain(order => fetchUserTask(order.userId)),\n  TE.chain(user => chargePaymentTask(user, order.total))\n)","handlingStrategy":"validation","validationCode":"const order = await fetchOrder(orderId)\nif (order == null) return { kind: 'NoOrder', orderId }","typeGuard":"const isOrder = (o: unknown): o is Order =>\n  typeof o === 'object' && o !== null && 'userId' in o && Array.isArray((o as Order).items)","tryCatchPattern":"try {\n  const order = await fetchOrder(orderId)\n  if (!order) throw new Error('No order')\n} catch (e) {\n  if (e instanceof Error && e.message === 'No order') return { kind: 'NoOrder', orderId }\n  throw e\n}","preventionTips":["Validate orderId format before the fetch","Keep fetch functions honest: null only for missing, throw only for failure","Prefer a composed pipeline (pipe + TE.chain) over sequential if-throw ladders"],"tags":["documentation","domain-error","railway-oriented","fp-ts"],"backgroundTag":"entity-not-found","analyzedSha":"58d857988fcfac6986206bca2b2fe223aa437e4b","analyzedAt":"2026-08-26T11:55:59.350Z","schemaVersion":2},"datasetVersion":"2026-08-26T14:46:13.012Z"}