{"record":{"id":"39d9e26504bb5eb9","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-urls","errorCode":"error-invalid-urls","errorMessage":"Invalid URLs","messagePattern":"Invalid URLs","errorType":"validation","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/lib/integrations/lib/validateOutgoingIntegration.ts","lineNumber":40,"sourceCode":"\t\tthrow new Meteor.Error('error-invalid-event-type', 'Invalid event type', {\n\t\t\tfunction: 'validateOutgoing._verifyRequiredFields',\n\t\t});\n\t}\n\n\tif (!integration.username || !Match.test(integration.username, String) || integration.username.trim() === '') {\n\t\tthrow new Meteor.Error('error-invalid-username', 'Invalid username', {\n\t\t\tfunction: 'validateOutgoing._verifyRequiredFields',\n\t\t});\n\t}\n\n\tif (outgoingEvents[integration.event].use.targetRoom && !integration.targetRoom) {\n\t\tthrow new Meteor.Error('error-invalid-targetRoom', 'Invalid Target Room', {\n\t\t\tfunction: 'validateOutgoing._verifyRequiredFields',\n\t\t});\n\t}\n\n\tif (!Match.test(integration.urls, [String])) {\n\t\tthrow new Meteor.Error('error-invalid-urls', 'Invalid URLs', {\n\t\t\tfunction: 'validateOutgoing._verifyRequiredFields',\n\t\t});\n\t}\n\n\tintegration.urls = integration.urls.filter((url) => url && url.trim() !== '');\n\n\tif (integration.urls.length === 0) {\n\t\tthrow new Meteor.Error('error-invalid-urls', 'Invalid URLs', {\n\t\t\tfunction: 'validateOutgoing._verifyRequiredFields',\n\t\t});\n\t}\n}\n\nasync function _verifyUserHasPermissionForChannels(userId: IUser['_id'], channels: string[]): Promise<void> {\n\tfor (let channel of channels) {\n\t\tif (scopedChannels.includes(channel)) {\n\t\t\tif (channel === 'all_public_channels') {\n\t\t\t\t// No special permissions needed to add integration to public channels","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/integrations/lib/validateOutgoingIntegration.ts#L22-L58","documentation":"First of the two 'error-invalid-urls' failures in _verifyRequiredFields: Match.test(integration.urls, [String]) fails when urls is missing, not an array, or an array containing non-string entries. The REST layer does not coerce this field, so the exact shape — an array of strings — must arrive intact.","triggerScenarios":"POST /api/v1/integrations.create with urls as a single string ('https://a.example/hook'), a comma-separated string, an array of objects, or omitted entirely for an outgoing integration.","commonSituations":"Writers assuming the API accepts a CSV like the channel field does; form code that sends one URL as a bare string when only one endpoint is configured; JSON payloads built by hand where the array brackets are lost.","solutions":["Send urls as an array of strings: urls: ['https://a.example/hook']","Split comma-separated input before submitting: urls: csv.split(',').map((u) => u.trim())","Check the outgoing integrations REST examples in the docs, which show the array form"],"exampleFix":"// before\n{ urls: 'https://a.example/hook,https://b.example/hook' }\n\n// after\n{ urls: ['https://a.example/hook', 'https://b.example/hook'] }","handlingStrategy":"validation","validationCode":"if (!Array.isArray(urls) || !urls.every((u) => typeof u === 'string')) {\n  throw new TypeError('urls must be an array of strings');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Submit urls as an array even when there is exactly one endpoint","Split comma-separated form input before calling the API"],"tags":["integrations","outgoing-webhook","validation","urls"],"backgroundTag":"schema-validation-failed","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}