koala73/worldmonitor · error · ConvexError

UNAUTHENTICATED

UNAUTHENTICATED

Error message

UNAUTHENTICATED

What it means

A ConvexError thrown by the setChannel mutation when ctx.auth.getUserIdentity() returns null, meaning the caller invoked the mutation without a valid authenticated identity (no auth token, expired session, or anonymous call). It fires before any channel fields are validated or written, preventing unauthenticated users from creating or modifying notificationChannels. It is a generic auth sentinel; the input at fault is the request itself lacking credentials. Clients must authenticate before calling setChannel.

Solutions

  1. Ensure the Clerk session is established before the channel-settings UI saves
  2. Handle the UNAUTHENTICATED ConvexError by prompting sign-in
Defensive patterns

Strategy: validation

When it happens

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

Common situations: See trigger scenarios.

Understand the failure class


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

Appendix: source

Thrown at convex/notificationChannels.ts:518

      .withIndex("by_user", (q) => q.eq("userId", identity.subject))
      .collect();
    return channels.map(channel => (channel.channelType === "email" && channel.emailOwnership !== "verified_account")
      || (channel.channelType === "telegram" && channel.telegramOwnership !== "verified_callback")
      ? { ...channel, verified: false } : channel);
  },
});

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) {

View on GitHub (pinned to e586b8b4b8)