RocketChat/Rocket.Chat · error · Error

username-required

Error message

username-required

What it means

Thrown by POST /hooks/add/:integrationId/:userId/:token (legacy Zapier-style integration webhook) when event is 'newMessageToUser' but bodyParams.data.username is missing or empty. The outgoing integration needs a @username channel to post into, so creation aborts with the plain error 'username-required'. Note the code checks the '@' prefix before existence, so a missing username always falls through to this throw.

Solutions

  1. Include data.username (bare username is fine; server prepends '@') in the POST body for newMessageToUser events
  2. Switch the event to newMessageOnChannel and supply data.channel_name if you meant a channel
  3. Validate the payload shape before firing the webhook (event-specific required keys)
  4. Check the integration webhook logs (incomingLogger) to confirm which branch ran

Example fix

// before
await fetch(`${rc}/api/v1/hooks/add/${iid}/${uid}/${tok}`, { method: 'POST', body: JSON.stringify({ event: 'newMessageToUser', name: 'zap', target_url: 'https://cb.example' }) });
// after
await fetch(`${rc}/api/v1/hooks/add/${iid}/${uid}/${tok}`, { method: 'POST', body: JSON.stringify({ event: 'newMessageToUser', name: 'zap', target_url: 'https://cb.example', data: { username: 'jon.doe' } }) });
Defensive patterns

Strategy: validation

Validate before calling

function validateHooksAddPayload(p: {event:string; name:string; target_url:string; data?:{channel_name?:string; username?:string}}) {
  if (p.event === 'newMessageToUser' && !p.data?.username) throw new Error('username-required: data.username missing');
  if (p.event === 'newMessageOnChannel' && !p.data?.channel_name) throw new Error('channel_name required');
}

Type guard

const isMessageToUserPayload = (p: unknown): p is {event:'newMessageToUser'; name:string; target_url:string; data:{username:string}} =>
  typeof p === 'object' && p !== null && (p as {event?:string}).event === 'newMessageToUser' && typeof ((p as {data?:{username?:string}}).data)?.username === 'string' && ((p as {data:{username:string}}).data.username.length > 0);

Try / catch

try { await postHooksAdd(payload); } catch (e) { if (/username-required/.test(String(e?.message))) { payload.data = { ...payload.data, username: fallbackUser }; await postHooksAdd(payload); } else throw e; }

Prevention

When it happens

Trigger: POST to /api/v1/hooks/add/... with {event:'newMessageToUser', name:'x', target_url:'https://cb'} and no data object; data:{trigger_words:[...]} without username; username:'' (empty string gets auto-prefixed to '@' and behaves unexpectedly — always send a real username).

Common situations: Zapier-style flows copied from the channel template (newMessageOnChannel uses channel_name) without swapping to username; form integrations with optional username left blank; version drift in a fields mapper dropping the username key.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18). Data as JSON: /api/errors/d9a4a734045e3607. Report an issue: GitHub.

Appendix: source

Thrown at apps/meteor/server/api/webhooks.ts:86

				urls: [options.target_url],
				name: options.name,
				channel: options.data.channel_name,
				triggerWords: options.data.trigger_words,
				type: 'webhook-outgoing',
				event: 'sendMessage',
				token: Random.id(24),
				scriptEnabled: false,
				script: '',
				enabled: true,
				_id: Random.id(),
				_updatedAt: new Date(),
			});
		case 'newMessageToUser':
			if (options.data?.username?.indexOf('@') === -1) {
				options.data.username = `@${options.data.username}`;
			}
			if (!options.data?.username) {
				throw new Error('username-required');
			}

			return addOutgoingIntegration(user._id, {
				username: 'rocket.cat',
				urls: [options.target_url],
				name: options.name,
				channel: options.data.username,
				triggerWords: options.data.trigger_words,
				_id: '',
				type: 'webhook-outgoing',
				token: '',
				scriptEnabled: false,
				script: '',
				enabled: false,
				_updatedAt: new Date(),
				event: 'sendMessage',
			});
	}

View on GitHub (pinned to b2c16d5842)