RocketChat/Rocket.Chat · error · Meteor.Error

error-no-file-uploaded

error-no-file-uploaded

Error message

No file was uploaded

What it means

Thrown by POST rooms.upload/:rid (multipart) when MultipartUploadHandler.parseRequest returns no 'file' part. The handler expects a multipart form with a 'file' field capped by FileUpload_MaxFileSize. Reaching this branch means the request either had no file field, failed file-size handling, or was not multipart at all.

Source

Thrown at apps/meteor/server/api/v1/rooms.ts:281

	},
);

API.v1.addRoute(
	'rooms.media/:rid',
	{ authRequired: true },
	{
		async post() {
			if (!(await canAccessRoomIdAsync(this.urlParams.rid, this.userId))) {
				return API.v1.forbidden();
			}

			const { file, fields } = await MultipartUploadHandler.parseRequest(this.incoming, {
				field: 'file',
				maxSize: settings.get<number>('FileUpload_MaxFileSize'),
			});

			if (!file) {
				throw new Meteor.Error('error-no-file-uploaded', 'No file was uploaded');
			}

			const expiresAt = new Date();
			expiresAt.setHours(expiresAt.getHours() + 24);

			let content;

			if (fields.content) {
				try {
					content = JSON.parse(fields.content);
				} catch (e) {
					console.error(e);
					throw new Meteor.Error('invalid-field-content');
				}
			}

			const details = {
				name: file.filename,

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Send the request as multipart/form-data with a part literally named 'file'.
  2. In axios/fetch/Postman, use FormData and append('file', blob, name) — do not JSON.stringify the body.
  3. Confirm FileUpload_MaxFileSize in admin settings is greater than your file size and > 0.
  4. If using the resumable/Streamer flow for large files, use rooms.mediaConfirm instead of rooms.upload.

Example fix

// before (wrong: JSON body)
await rest.post(`/api/v1/rooms.upload/${rid}`, { file: base64 });

// after (multipart with field 'file')
const form = new FormData();
form.append('file', fileBlob, fileBlob.name);
await rest.post(`/api/v1/rooms.upload/${rid}`, form);
Defensive patterns

Strategy: validation

Validate before calling

function buildUploadForm(file: Blob, fields?: Record<string, string>): FormData {
  if (!(file instanceof Blob)) throw new TypeError('file must be a Blob/File');
  const form = new FormData();
  form.append('file', file, (file as File).name || 'upload.bin');
  for (const [k, v] of Object.entries(fields ?? {})) form.append(k, v);
  return form;
}

Type guard

function isMultipartReady(form: FormData): boolean {
  return form.has('file');
}

Try / catch

try {
  await rest.post(`/api/v1/rooms.upload/${rid}`, form, { headers: form.getHeaders?.() });
} catch (e) {
  if (isMeteorError(e, 'error-no-file-uploaded')) {
    // verify field name is 'file' and Content-Type is multipart/form-data
  } else throw e;
}

Prevention

When it happens

Trigger: POST /api/v1/rooms.upload/:rid with a JSON body instead of multipart/form-data; multipart request whose file field is named something other than 'file'; empty form; file rejected upstream of the handler so 'file' is undefined.

Common situations: Client forgetting to set Content-Type: multipart/form-data; using 'attachment' or 'upload' as the field name; file uploads disabled or FileUpload_MaxFileSize set to 0; proxy/gateway stripping the multipart boundary.

Related errors


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