{"record":{"id":"161e8498a5277490","repo":"koala73/worldmonitor","slug":"email-required-for-email-channel","errorCode":null,"errorMessage":"email required for email channel","messagePattern":"email required for email channel","errorType":"exception","errorClass":"ConvexError","httpStatus":null,"severity":"error","filePath":"convex/notificationChannels.ts","lineNumber":540,"sourceCode":"    const existing = await ctx.db\n      .query(\"notificationChannels\")\n      .withIndex(\"by_user_channel\", (q) =>\n        q.eq(\"userId\", userId).eq(\"channelType\", args.channelType),\n      )\n      .unique();\n\n    const now = Date.now();\n\n    if (args.channelType === \"telegram\") {\n      throw new ConvexError(\"telegram channel must be linked through bot pairing\");\n    } else if (args.channelType === \"slack\") {\n      if (!args.webhookEnvelope) throw new ConvexError(\"webhookEnvelope required for slack channel\");\n      const doc = { userId, channelType: \"slack\" as const, webhookEnvelope: args.webhookEnvelope, verified: true, linkedAt: now };\n      if (existing) {\n        await ctx.db.replace(existing._id, doc);\n      } else {\n        await ctx.db.insert(\"notificationChannels\", doc);\n      }\n    } else if (args.channelType === \"email\") {\n      const email = requireVerifiedAccountEmail(args.email, identity.emailVerified === true ? identity.email : undefined);\n      const doc = { userId, channelType: \"email\" as const, email, emailOwnership: \"verified_account\" as const, verified: true, linkedAt: now };\n      if (existing) {\n        await ctx.db.replace(existing._id, doc);\n      } else {\n        await ctx.db.insert(\"notificationChannels\", doc);\n      }\n    } else if (args.channelType === \"webhook\") {\n      if (!args.webhookEnvelope) throw new ConvexError(\"webhookEnvelope required for webhook channel\");\n      const doc = { userId, channelType: \"webhook\" as const, webhookEnvelope: args.webhookEnvelope, verified: true, linkedAt: now, webhookLabel: args.webhookLabel };\n      if (existing) {\n        await ctx.db.replace(existing._id, doc);\n      } else {\n        await ctx.db.insert(\"notificationChannels\", doc);\n      }\n    } else {\n      throw new ConvexError(\"discord channel must be set via set-discord-oauth\");","sourceCodeStart":522,"sourceCodeEnd":558,"githubUrl":"https://github.com/koala73/worldmonitor/blob/e586b8b4b80f595aa7ece295eec10d76f2921240/convex/notificationChannels.ts#L522-L558","documentation":"Channel-shape validation in setChannel: channelType is 'email' but args.email is missing. Email channels store the delivery address as their payload, so the channel document cannot be created without it.","triggerScenarios":"Thrown at convex/notificationChannels.ts:509 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Collect and submit the email address with the channel settings","Require the email field in the UI when email is the selected channel type"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"e586b8b4b80f595aa7ece295eec10d76f2921240","analyzedAt":"2026-08-21T16:51:25.751Z","contentChangedAt":"2026-08-21T16:51:25.751Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}