RocketChat/Rocket.Chat · error · Meteor.Error

error-not-allowed

error-not-allowed

Error message

Change avatar is not allowed

What it means

avatarsOnFinishUpload (FileUpload.ts:449-452) runs when a file finishes uploading to the Avatars store. For non-room files (no file.rid) it must bind the avatar to a user; if the upload record has no userId it throws error-not-allowed 'Change avatar is not allowed'. The userId is derived from the upload request's authenticated context, so a missing one means the upload arrived without a valid user.

Source

Thrown at apps/meteor/server/lib/media/file-upload/lib/FileUpload.ts:449

			size = await MultipartUploadHandler.stripExifFromFile(tmpFile);
		}

		await this.getCollection().updateOne(
			{ _id: file._id },
			{
				$set: { size, identify },
			},
			options,
		);
	},

	async avatarsOnFinishUpload(file: IUpload) {
		if (file.rid) {
			return;
		}

		if (!file.userId) {
			throw new Meteor.Error('error-not-allowed', 'Change avatar is not allowed');
		}

		// update file record to match user's username
		const user = await Users.findOneById(file.userId);
		if (!user?.username) {
			throw new Meteor.Error('error-not-allowed', 'Change avatar is not allowed');
		}
		const oldAvatar = await Avatars.findOneByName(user.username);
		if (oldAvatar) {
			await Avatars.deleteFile(oldAvatar._id);
		}
		await Avatars.updateFileNameById(file._id, user.username);
	},

	async getRequestUserId({ headers = {}, url }: http.IncomingMessage): Promise<string | undefined> {
		if (!url) {
			return undefined;
		}

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Upload avatars through the supported flows: the UI avatar dialog or the users.setAvatar REST endpoint with a valid auth token
  2. When hitting the raw upload URL, include valid X-User-Id/X-Auth-Token headers or a logged-in cookie session
  3. Verify the URL you POST to is the one returned by the avatar upload API, not a hand-built one
  4. If writing server code, ensure the upload record carries userId before the store finishes
Defensive patterns

Strategy: validation

Validate before calling

// before POSTing to the avatar upload URL
const userId = await resolveCurrentUserId();
if (!userId) throw new Error('Avatar upload requires an authenticated user');

Try / catch

try {
  await uploadAvatar(file);
} catch (error: any) {
  if (error instanceof Meteor.Error && error.error === 'error-not-allowed' && /avatar/i.test(error.reason)) {
    reauthenticateAndRetry(); // upload arrived without a user binding
    return;
  }
  throw error;
}

Prevention

When it happens

Trigger: POSTing directly to the avatar file-upload URL without X-Auth-Token/X-User-Id headers or a valid session cookie; uploads whose request-user resolution (getRequestUserId) fails because the URL is malformed; anonymous uploads to the Avatars store.

Common situations: Custom scripts calling the raw upload endpoint instead of users.setAvatar; expired auth tokens where the file POST succeeds but the user cannot be resolved; load balancers/proxies stripping auth headers; broken federation/omnichannel avatar flows.

Related errors


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