{"record":{"id":"2e329f8fa2afdd1f","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-channel-2e329f","errorCode":"error-invalid-channel","errorMessage":"Invalid channel","messagePattern":"Invalid channel","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/meteor-methods/integrations/incoming/updateIncomingIntegration.ts","lineNumber":27,"sourceCode":"import { compileIntegrationScript } from '../../../lib/integrations/lib/compileIntegrationScript';\nimport { isScriptEngineFrozen, validateScriptEngine } from '../../../lib/integrations/lib/validateScriptEngine';\nimport { notifyOnIntegrationChanged } from '../../../lib/notifyListener';\n\nconst validChannelChars = ['@', '#'];\n\ndeclare module '@rocket.chat/ddp-client' {\n\t// eslint-disable-next-line @typescript-eslint/naming-convention\n\tinterface ServerMethods {\n\t\tupdateIncomingIntegration(\n\t\t\tintegrationId: string,\n\t\t\tintegration: INewIncomingIntegration | IUpdateIncomingIntegration,\n\t\t): IIntegration | null;\n\t}\n}\n\nfunction validateChannels(channelString: string | undefined): string[] {\n\tif (!channelString || typeof channelString.valueOf() !== 'string' || channelString.trim() === '') {\n\t\tthrow new Meteor.Error('error-invalid-channel', 'Invalid channel', {\n\t\t\tmethod: 'updateIncomingIntegration',\n\t\t});\n\t}\n\n\tconst channels = channelString.split(',').map((channel) => channel.trim());\n\n\tfor (const channel of channels) {\n\t\tif (!validChannelChars.includes(channel[0])) {\n\t\t\tthrow new Meteor.Error('error-invalid-channel-start-with-chars', 'Invalid channel. Start with @ or #', {\n\t\t\t\tmethod: 'updateIncomingIntegration',\n\t\t\t});\n\t\t}\n\t}\n\n\treturn channels;\n}\n\nexport const updateIncomingIntegration = async (","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/integrations/incoming/updateIncomingIntegration.ts#L9-L45","documentation":"Thrown by updateIncomingIntegration's validateChannels when integration.channel is missing, not a string, or blank (all three conditions combined at one throw site, line 27). Unlike a partial-update API, this DDP method requires the full channel string on every update call - omitting channel to 'keep it as is' fails here.","triggerScenarios":"Meteor.callAsync('updateIncomingIntegration', id, { name: 'new-name' }) with no channel key; an edit form that submits an empty channel field; passing channel as an array of room objects.","commonSituations":"Developers assuming PATCH-like semantics on a method that validates channel unconditionally; UI edit screens where clearing the channel input sends ''; migration from /api/v1/integrations.update which likewise requires channel.","solutions":["Always include the complete comma-separated channel string ('#room,@user') in the update payload, echoing the integration's current channels when unchanged","Load the current integration first (GET /api/v1/integrations.list) and reuse its channel list joined with ','","Migrate to the REST endpoint /v1/integrations.update before 9.0.0 removes the method"],"exampleFix":"// before: partial update, channel omitted\nawait Meteor.callAsync('updateIncomingIntegration', id, { enabled: true }); // -> error-invalid-channel\n// after: include current channels\nawait Meteor.callAsync('updateIncomingIntegration', id, { enabled: true, channel: current.channel.join(',') });","handlingStrategy":"validation","validationCode":"const current = await Meteor.callAsync('listIncomingIntegrations').then((r) => r.integrations.find((i) => i._id === integrationId));\nconst channel = integration.channel ?? current.channel.join(','); // always send a full channel string\nif (typeof channel !== 'string' || channel.trim() === '') throw new Error('channel is required on update');\nawait Meteor.callAsync('updateIncomingIntegration', integrationId, { ...integration, channel });","typeGuard":"const hasChannelString = (p: { channel?: unknown }): p is { channel: string } => typeof p.channel === 'string' && p.channel.trim() !== '';","tryCatchPattern":"try {\n  await Meteor.callAsync('updateIncomingIntegration', integrationId, integration);\n} catch (err) {\n  if (err instanceof Meteor.Error && err.error === 'error-invalid-channel') { /* merge current channels into payload and resubmit */ }\n}","preventionTips":["Treat update as full-replace, not PATCH: always resend channel","Echo the current channel list from the loaded record","Keep edit forms backed by the fetched integration object"],"tags":["rocket-chat","incoming-integration","channel-validation","meteor-method"],"backgroundTag":"integration-channel-validation","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}