{"record":{"id":"0d004ebd421b5293","repo":"koala73/worldmonitor","slug":"unauthenticated-0d004e","errorCode":"UNAUTHENTICATED","errorMessage":"UNAUTHENTICATED","messagePattern":"UNAUTHENTICATED","errorType":"exception","errorClass":"ConvexError","httpStatus":null,"severity":"error","filePath":"convex/notificationChannels.ts","lineNumber":518,"sourceCode":"      .withIndex(\"by_user\", (q) => q.eq(\"userId\", identity.subject))\n      .collect();\n    return channels.map(channel => (channel.channelType === \"email\" && channel.emailOwnership !== \"verified_account\")\n      || (channel.channelType === \"telegram\" && channel.telegramOwnership !== \"verified_callback\")\n      ? { ...channel, verified: false } : channel);\n  },\n});\n\nexport const setChannel = mutation({\n  args: {\n    channelType: channelTypeValidator,\n    chatId: v.optional(v.string()),\n    webhookEnvelope: v.optional(v.string()),\n    email: v.optional(v.string()),\n    webhookLabel: v.optional(v.string()),\n  },\n  handler: async (ctx, args) => {\n    const identity = await ctx.auth.getUserIdentity();\n    if (!identity) throw new ConvexError(\"UNAUTHENTICATED\");\n    const userId = identity.subject;\n    await assertProEntitlement(ctx, userId);\n\n    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) {","sourceCodeStart":500,"sourceCodeEnd":536,"githubUrl":"https://github.com/koala73/worldmonitor/blob/e586b8b4b80f595aa7ece295eec10d76f2921240/convex/notificationChannels.ts#L500-L536","documentation":"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.","triggerScenarios":"Thrown at convex/notificationChannels.ts:479 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Ensure the Clerk session is established before the channel-settings UI saves","Handle the UNAUTHENTICATED ConvexError by prompting sign-in"],"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"}