koala73/worldmonitor · error · ConvexError

chatId required for telegram channel

Error message

chatId required for telegram channel

What it means

Channel-shape validation in setChannel: channelType is 'telegram' but args.chatId is missing. Telegram channels store the chat id as their payload, so the channel document cannot be constructed without it.

Solutions

  1. Collect the Telegram chat id (e.g. via the bot pairing flow) before saving the channel
  2. Require the chatId field in the UI when telegram is the selected channel type
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at convex/notificationChannels.ts:493 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of koala73/worldmonitor@e586b8b4b8 (2026-08-21). Data as JSON: /api/errors/a071d12540763eae. Report an issue: GitHub.

Appendix: source

Thrown at convex/notificationChannels.ts:524

});

export const setChannel = mutation({
  args: {
    channelType: channelTypeValidator,
    chatId: v.optional(v.string()),
    webhookEnvelope: v.optional(v.string()),
    email: v.optional(v.string()),
    webhookLabel: v.optional(v.string()),
  },
  handler: async (ctx, args) => {
    const identity = await ctx.auth.getUserIdentity();
    if (!identity) throw new ConvexError("UNAUTHENTICATED");
    const userId = identity.subject;
    await assertProEntitlement(ctx, userId);

    const existing = await ctx.db
      .query("notificationChannels")
      .withIndex("by_user_channel", (q) =>
        q.eq("userId", userId).eq("channelType", args.channelType),
      )
      .unique();

    const now = Date.now();

    if (args.channelType === "telegram") {
      throw new ConvexError("telegram channel must be linked through bot pairing");
    } else if (args.channelType === "slack") {
      if (!args.webhookEnvelope) throw new ConvexError("webhookEnvelope required for slack channel");
      const doc = { userId, channelType: "slack" as const, webhookEnvelope: args.webhookEnvelope, verified: true, linkedAt: now };
      if (existing) {
        await ctx.db.replace(existing._id, doc);
      } else {
        await ctx.db.insert("notificationChannels", doc);
      }
    } else if (args.channelType === "email") {
      const email = requireVerifiedAccountEmail(args.email, identity.emailVerified === true ? identity.email : undefined);

View on GitHub (pinned to e586b8b4b8)