{"record":{"id":"109549883cd38335","repo":"sickn33/agentic-awesome-skills","slug":"not-found","errorCode":null,"errorMessage":"Not found","messagePattern":"Not found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"skills/fp-async/SKILL.md","lineNumber":905,"sourceCode":"| Recover from error | `TE.orElse(fn)` |\n| Use default value | `TE.getOrElse(() => T.of(default))` |\n| Handle both cases | `TE.fold(onError, onSuccess)` |\n| Build up context | `TE.Do` + `TE.bind('name', () => te)` |\n| Log without changing | `TE.tap(fn)` |\n| Filter with error | `TE.filterOrElse(pred, toError)` |\n\n---\n\n## Before/After Summary\n\n### Fetching Data\n\n```typescript\n// BEFORE\nasync function getUser(id: string) {\n  try {\n    const res = await fetch(`/api/users/${id}`)\n    if (!res.ok) throw new Error('Not found')\n    return await res.json()\n  } catch (e) {\n    console.error(e)\n    return null\n  }\n}\n\n// 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```","sourceCodeStart":887,"sourceCodeEnd":923,"githubUrl":"https://github.com/sickn33/agentic-awesome-skills/blob/58d857988fcfac6986206bca2b2fe223aa437e4b/skills/fp-async/SKILL.md#L887-L923","documentation":"Illustrative error from the getUser BEFORE example near line 905: any non-2xx response to GET /api/users/:id throws 'Not found', and the surrounding catch then swallows every failure (including network errors) by logging and returning null. The skill presents this as the anti-pattern: one message for all HTTP failures plus silent fallback.","triggerScenarios":"Unknown user id (404); expired auth returning 401; server 500; network-failure rejected promise — all collapse to null after the catch.","commonSituations":"UI showing a blank profile because a 500 was silently converted to null; debugging made hard because the error only goes to console.error; developers cannot distinguish 'no such user' from 'request failed' without re-fetching manually.","solutions":["Stop returning null from catch — let callers see the failure","Branch on res.status so 404 means 'missing' and other statuses mean 'request failed'","Adopt the AFTER version (line ~918) using TE.tryCatch + E.toError so errors stay in the Left channel","Log with status and body, not just the Error object"],"exampleFix":"// before\nif (!res.ok) throw new Error('Not found')\ncatch (e) { console.error(e); return null }\n// after\nconst getUser = (id: string) =>\n  TE.tryCatch(async () => {\n    const res = await fetch(`/api/users/${id}`)\n    if (!res.ok) throw new Error(`HTTP ${res.status}`)\n    return res.json()\n  }, E.toError)\n// callers fold over Left instead of receiving null","handlingStrategy":"fallback","validationCode":"const res = await fetch(`/api/users/${id}`)\nif (!res.ok) {\n  if (res.status === 404) return { kind: 'UserNotFound' }\n  throw new Error(`HTTP ${res.status}`)\n}","typeGuard":"const isUser = (u: unknown): u is User =>\n  typeof u === 'object' && u !== null && 'id' in u","tryCatchPattern":"catch (e) {\n  // never blanket-return null; classify and rethrow or return a typed result\n  if (e instanceof Error && e.message === 'Not found') return { kind: 'UserNotFound' }\n  throw e\n}","preventionTips":["Do not swallow errors into null — callers cannot tell missing from broken","Branch on status codes before throwing","Reserve console.error for diagnostics, never as control flow"],"tags":["documentation","fetch","swallowed-error","fp-ts"],"backgroundTag":"fetch-non-2xx-response","analyzedSha":"58d857988fcfac6986206bca2b2fe223aa437e4b","analyzedAt":"2026-08-26T11:55:59.350Z","schemaVersion":2},"datasetVersion":"2026-08-26T14:46:13.012Z"}