{"record":{"id":"587e97c29fa231ef","repo":"sickn33/agentic-awesome-skills","slug":"invalid-email","errorCode":null,"errorMessage":"Invalid email","messagePattern":"Invalid email","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"skills/fp-pragmatic/SKILL.md","lineNumber":468,"sourceCode":"// Use it\npipe(\n  getManagerEmail(employee),\n  O.fold(\n    () => sendToDefault(),\n    (email) => sendTo(email)\n  )\n)\n```\n\n### Validation with Multiple Checks\n\n```typescript\n// Before: Throws on first error\nfunction validateUser(data: unknown): User {\n  if (!data || typeof data !== 'object') throw new Error('Must be object')\n  const obj = data as Record<string, unknown>\n  if (typeof obj.email !== 'string') throw new Error('Email required')\n  if (!obj.email.includes('@')) throw new Error('Invalid email')\n  if (typeof obj.age !== 'number') throw new Error('Age required')\n  if (obj.age < 0) throw new Error('Age must be positive')\n  return obj as User\n}\n\n// After: Returns first error, type-safe\nconst validateUser = (data: unknown): E.Either<string, User> =>\n  pipe(\n    E.Do,\n    E.bind('obj', () =>\n      typeof data === 'object' && data !== null\n        ? E.right(data as Record<string, unknown>)\n        : E.left('Must be object')\n    ),\n    E.bind('email', ({ obj }) =>\n      typeof obj.email === 'string' && obj.email.includes('@')\n        ? E.right(obj.email)\n        : E.left('Valid email required')","sourceCodeStart":450,"sourceCodeEnd":486,"githubUrl":"https://github.com/sickn33/agentic-awesome-skills/blob/58d857988fcfac6986206bca2b2fe223aa437e4b/skills/fp-pragmatic/SKILL.md#L450-L486","documentation":"Third guard in the fp-pragmatic validateUser example (skills/fp-pragmatic/SKILL.md:468). Thrown when email is a string but does not contain an @ character: a format check, distinct from the presence check at line 467.","triggerScenarios":"validateUser with email values like not-an-email, an empty string (no @), or userexample.com; note that the naive includes(@) check also lets malformed values like a@b pass.","commonSituations":"Free-text inputs with no client-side validation; typos; paste errors dropping the @; test fixtures with placeholder strings. Because the check is only includes(@), real code should use a proper regex or schema email format.","solutions":["Replace the naive includes(@) with a real email format check: zod z.string().email(), a well-tested regex, or HTML5 input[type=email] plus server-side validation","Collect this alongside other field errors using the doc Either-accumulating AFTER version","Normalize (trim, lowercase) email before validating to avoid whitespace-driven false negatives"],"exampleFix":"// before\nif (!obj.email.includes('@')) throw new Error('Invalid email')\n\n// after\nconst EmailSchema = z.string().trim().toLowerCase().email()\nconst parsed = EmailSchema.safeParse(obj.email)\nif (!parsed.success) errors.push('Invalid email')","handlingStrategy":"validation","validationCode":"const EMAIL_RE = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\nconst email = String(data.email ?? '').trim()\nif (!EMAIL_RE.test(email)) {\n  return badRequest('email format is invalid')\n}","typeGuard":"const isValidEmail = (s: string): boolean =>\n  /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(s.trim())","tryCatchPattern":null,"preventionTips":["Use z.string().email() or an established regex instead of includes(@)","Trim and lowercase email before validating","Combine format checks with presence checks in one schema so users see all errors"],"tags":["validation","email-format","schema"],"backgroundTag":"schema-validation-failed","analyzedSha":"58d857988fcfac6986206bca2b2fe223aa437e4b","analyzedAt":"2026-08-26T11:55:59.350Z","schemaVersion":2},"datasetVersion":"2026-08-26T14:46:13.012Z"}