{"record":{"id":"4418fd2d6f03700f","repo":"RocketChat/Rocket.Chat","slug":"invalid-channel-4418fd","errorCode":"invalid-channel","errorMessage":"invalid-channel","messagePattern":"invalid-channel","errorType":"error_code","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/lib/messages/processWebhookMessage.ts","lineNumber":93,"sourceCode":"\t\t\t\terrorOnEmpty: false,\n\t\t\t});\n\t\t\tif (room) {\n\t\t\t\treturn room;\n\t\t\t}\n\n\t\t\t// We didn't get a room, let's try finding direct messages\n\t\t\troom = await getRoomByNameOrIdWithOptionToJoin({\n\t\t\t\tuser,\n\t\t\t\tnameOrId: _channelValue,\n\t\t\t\ttryDirectByUserIdOnly: true,\n\t\t\t\ttype: 'd',\n\t\t\t});\n\t\t\tif (room) {\n\t\t\t\treturn room;\n\t\t\t}\n\n\t\t\t// No room, so throw an error\n\t\t\tthrow new Meteor.Error('invalid-channel');\n\t}\n};\n\nconst buildMessage = (messageObj: Payload, defaultValues: DefaultValues) => {\n\tconst message: Partial<IMessage> & { parseUrls?: boolean } = {\n\t\talias: messageObj.username || messageObj.alias || defaultValues.alias,\n\t\tmsg: trim(messageObj.text || messageObj.msg || ''),\n\t\tattachments: messageObj.attachments || [],\n\t\tparseUrls: messageObj.parseUrls !== undefined ? messageObj.parseUrls : !messageObj.attachments,\n\t\tbot: messageObj.bot,\n\t\tgroupable: messageObj.groupable !== undefined ? messageObj.groupable : false,\n\t\ttmid: messageObj.tmid,\n\t\tcustomFields: messageObj.customFields,\n\t};\n\n\tif (!_.isEmpty(messageObj.icon_url) || !_.isEmpty(messageObj.avatar)) {\n\t\tmessage.avatar = messageObj.icon_url || messageObj.avatar;\n\t} else if (!_.isEmpty(messageObj.icon_emoji) || !_.isEmpty(messageObj.emoji)) {","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/messages/processWebhookMessage.ts#L75-L111","documentation":"While resolving an incoming-webhook channel target (processWebhookMessage.ts:53-94), channel strings not prefixed with '#' or '@' fall into the default branch: the room is looked up by name/id (with auto-join), then as a direct room containing the webhook user and the value treated as a user id; if neither matches, the server throws Meteor.Error 'invalid-channel'. The same code also surfaces from getRoomByNameOrIdWithOptionToJoin when '#name'/'@user' targets do not exist or have the wrong type.","triggerScenarios":"An incoming webhook payload with channel '#typo-general', '@deleted-user', a raw room id that no longer exists, or an unknown prefix like '!chan'; '@' targets whose DM room doesn't exist yet and whose id doesn't match a user; channel renamed or deleted after the integration was configured.","commonSituations":"Webhook integrations (CI, alerting, Zapier-style) configured with a channel that was later renamed/deleted; DM targets whose username changed; sending to private rooms by name from a bot that cannot resolve them; separateResponse=false so the whole request aborts on one bad channel.","solutions":["Verify the target exists and spell it exactly: '#channelName' for channels/groups, '@username' for direct messages","Re-create the channel or update the webhook's channel field after renames/deletions","For DMs, prefer the target's username over raw user id - DM rooms are found (or created) via the user record","Set separateResponse: true in the payload so one bad channel returns a per-channel error instead of failing the entire delivery"],"exampleFix":"// before: { \"channel\": \"#general-typo\", ... } -> invalid-channel\n// after: { \"channel\": \"#general\", \"separateResponse\": true, ... }","handlingStrategy":"validation","validationCode":"// before sending, verify the target resolves for the integration user\nconst room = await getRoomByNameOrIdWithOptionToJoin({\n  user: botUser,\n  nameOrId: channel.replace(/^[#@]/, ''),\n  type: channel.startsWith('@') ? 'd' : undefined,\n});\nif (!room) throw new Error(`Unknown channel ${channel} - fix the webhook config`);","typeGuard":null,"tryCatchPattern":"try {\n  await processWebhookMessage(msg, user, { ... });\n} catch (error: any) {\n  if (error instanceof Meteor.Error && error.error === 'invalid-channel') {\n    // bad/deleted/renamed channel in payload; fix config, do not blind-retry\n    alertChannelConfigError(payload.channel);\n    return;\n  }\n  throw error;\n}","preventionTips":["Use '#name' for channels and '@username' for DMs exactly","Re-check webhook channel config after every channel rename/delete","Set separateResponse:true for multi-channel deliveries"],"tags":["webhook","integration","channel","incoming-webhook","not-found"],"backgroundTag":"channel-not-found","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}