{"record":{"id":"6fd434d7a9a3622c","repo":"koala73/worldmonitor","slug":"valid-email-is-required","errorCode":null,"errorMessage":"Valid email is required","messagePattern":"Valid email is required","errorType":"validation","errorClass":"ConvexError","httpStatus":null,"severity":"error","filePath":"convex/contactMessages.ts","lineNumber":66,"sourceCode":"    organization: v.optional(v.string()),\n    phone: v.optional(v.string()),\n    message: v.optional(v.string()),\n    source: v.string(),\n  },\n  handler: async (ctx, args) => {\n    // Length / shape validation. Reject obviously-bogus input before\n    // it reaches the table — also a defence against prompt-injection\n    // payloads enormous enough to trip downstream LLM cost.\n    const name = clip(args.name, MAX_NAME);\n    const email = clip(args.email, MAX_EMAIL);\n    const organization = clip(args.organization, MAX_ORG);\n    const phone = clip(args.phone, MAX_PHONE);\n    const message = clip(args.message, MAX_MESSAGE, { preserveNewlines: true });\n    const source = clip(args.source, MAX_SOURCE) ?? \"unknown\";\n\n    if (!name) throw new ConvexError(\"Name is required\");\n    if (!email || !EMAIL_RE.test(email)) {\n      throw new ConvexError(\"Valid email is required\");\n    }\n    if (!isCorporateDomain(email)) {\n      throw new ConvexError({\n        kind: \"FREE_EMAIL_NOT_ALLOWED\",\n        message: \"Please use a corporate email address.\",\n      });\n    }\n\n    const normalizedEmail = email.toLowerCase();\n\n    // Throttle: cap recent submissions per email. Index lookup keeps this O(matches),\n    // which the limit caps at PER_EMAIL_LIMIT + 1.\n    const windowStart = Date.now() - PER_EMAIL_WINDOW_MS;\n    const recent = await ctx.db\n      .query(\"contactMessages\")\n      .withIndex(\"by_normalized_email_received\", (q) =>\n        q.eq(\"normalizedEmail\", normalizedEmail).gte(\"receivedAt\", windowStart),\n      )","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/convex/contactMessages.ts#L48-L84","documentation":"Input validation in the contactMessages submit handler: args.email fails the email-format check. Bouncing malformed addresses before insert prevents junk rows and protects downstream email/LLM processing.","triggerScenarios":"Thrown at convex/contactMessages.ts:69 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Correct the email address in the form — the check requires a valid email shape","Add inline email-format validation in the UI before submit"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"7d06c8633d256c18e38133030bc3613976a96ec9","analyzedAt":"2026-08-21T16:51:25.751Z","contentChangedAt":"2026-08-21T16:51:25.751Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}