{"record":{"id":"82a74b23747a185f","repo":"sickn33/agentic-awesome-skills","slug":"id-required","errorCode":null,"errorMessage":"ID required","messagePattern":"ID required","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"skills/fp-errors/SKILL.md","lineNumber":43,"sourceCode":"- You need to replace exception-heavy code with `Either` or `TaskEither`.\n- The task involves validation, domain errors, or clearer error contracts in TypeScript.\n- You want pragmatic fp-ts error-handling guidance for real application code.\n\n---\n\n## 1. Stop Throwing Everywhere\n\n### The Problem with Exceptions\n\nExceptions are invisible in your types. They break the contract between functions.\n\n```typescript\n// What this function signature promises:\nfunction getUser(id: string): User\n\n// What it actually does:\nfunction getUser(id: string): User {\n  if (!id) throw new Error('ID required')\n  const user = db.find(id)\n  if (!user) throw new Error('User not found')\n  return user\n}\n\n// The caller has no idea this can fail\nconst user = getUser(id) // Might explode!\n```\n\nYou end up with code like this:\n\n```typescript\n// MESSY: try/catch everywhere\nfunction processOrder(orderId: string) {\n  let order\n  try {\n    order = getOrder(orderId)\n  } catch (e) {","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/sickn33/agentic-awesome-skills/blob/58d857988fcfac6986206bca2b2fe223aa437e4b/skills/fp-errors/SKILL.md#L25-L61","documentation":"Part of the hidden-failure-mode example in the fp-errors skill (skills/fp-errors/SKILL.md:43). It is thrown synchronously by getUser when called with an empty or falsy id, despite the signature function getUser(id: string): User promising an unconditional User. The doc uses it to show why unchecked exceptions make signatures lie.","triggerScenarios":"Calling getUser with an empty string or a nullish value cast to any: any falsy id fails the if (!id) guard before the db.find lookup happens.","commonSituations":"Passing an unvalidated request parameter or form field straight into a lookup function; optional path/route params defaulting to empty string; refactoring a signature to accept id without validating at the boundary.","solutions":["Validate and reject empty ids at the system boundary (request parsing) before calling getUser","Change the signature to make failure explicit: return Either of an error or User, or throw a typed ValidationError the caller must acknowledge","Use a branded non-empty-string type for id parameters"],"exampleFix":"// before\nfunction getUser(id: string): User {\n  if (!id) throw new Error('ID required')\n  // ...\n}\n\n// after\nconst getUser = (id: NonEmptyString): E.Either<UserError, User> =>\n  pipe(\n    db.find(id),\n    E.fromNullable({ tag: 'not-found' } as const)\n  )","handlingStrategy":"validation","validationCode":"const isNonEmpty = (s: string): boolean => s.trim().length > 0\nif (!isNonEmpty(id)) {\n  return badRequest('id must be a non-empty string')\n}","typeGuard":"type NonEmptyString = string & { readonly brand: unique symbol }\nconst nonEmpty = (s: string): s is NonEmptyString => s.trim().length > 0","tryCatchPattern":null,"preventionTips":["Validate route params at the request boundary","Use branded non-empty string types for ids","Make functions return Either instead of throwing for bad input"],"tags":["validation","unchecked-exception","typescript","documentation-example"],"backgroundTag":"empty-required-parameter","analyzedSha":"58d857988fcfac6986206bca2b2fe223aa437e4b","analyzedAt":"2026-08-26T11:55:59.350Z","schemaVersion":2},"datasetVersion":"2026-08-26T14:46:13.012Z"}