RocketChat/Rocket.Chat · warning

[UploadService] Failed to cleanup temp file: ${tempFilePath}

Error message

[UploadService] Failed to cleanup temp file: ${tempFilePath}

What it means

MultipartUploadHandler.cleanup best-effort deletes a temporary upload file with fs.promises.unlink and swallows failures with this console warn. The rejection usually means the file was already gone (ENOENT), the process lacks permission on the temp directory (EACCES), or the path lives on a filesystem/container the process cannot write to. Upload processing continues; repeated failures leave temp files accumulating in the OS temp dir.

Source

Thrown at apps/meteor/server/api/lib/MultipartUploadHandler.ts:42

	field: string;
	maxSize?: number;
	allowedMimeTypes?: string[];
	transforms?: Transform[]; // Optional transform pipeline (e.g., EXIF stripping)
	fileOptional?: boolean;
};

export class MultipartUploadHandler {
	static transforms = {
		stripExif(): Transform {
			return new ExifTransformer();
		},
	};

	static async cleanup(tempFilePath: string): Promise<void> {
		try {
			await fs.promises.unlink(tempFilePath);
		} catch (error: any) {
			console.warn(`[UploadService] Failed to cleanup temp file: ${tempFilePath}`, error);
		}
	}

	static async stripExifFromFile(tempFilePath: string): Promise<number> {
		const strippedPath = `${tempFilePath}.stripped`;

		try {
			const writeStream = fs.createWriteStream(strippedPath);

			await pipeline(fs.createReadStream(tempFilePath), new ExifTransformer(), writeStream);

			await fs.promises.rename(strippedPath, tempFilePath);

			return writeStream.bytesWritten;
		} catch (error) {
			void this.cleanup(strippedPath);

			throw error;

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Identify the errno in the logged error object: ENOENT is harmless, EACCES/EROFS are configuration problems
  2. For EACCES/EROFS, point TMPDIR to a writable directory owned by the Rocket.Chat process and mount it consistently across replicas
  3. ENOENT: look for duplicate cleanup calls for the same upload and deduplicate them
  4. If it recurs, monitor the temp directory growth to catch silent leftovers
Defensive patterns

Strategy: validation

Validate before calling

import { access, constants, unlink } from 'node:fs/promises';

async function cleanup(tempFilePath: string): Promise<void> {
	try {
		await access(tempFilePath, constants.W_OK);
		await unlink(tempFilePath);
	} catch (error: any) {
		if (error.code !== 'ENOENT') console.warn('[UploadService] Failed to cleanup temp file:', tempFilePath, error.code);
	}
}

Try / catch

try {
	await fs.promises.unlink(tempFilePath);
} catch (error: any) {
	if (error?.code !== 'ENOENT') console.warn(`[UploadService] Failed to cleanup temp file: ${tempFilePath}`, error);
}

Prevention

When it happens

Trigger: Double cleanup of the same temp path (retry logic after a failed upload); TMPDIR pointing to a directory with wrong ownership or a read-only mount; containers where the temp path was created in a different, since-replaced, container layer; external tmp reapers (systemd-tmpfiles) removing long-lived upload temp files.

Common situations: Kubernetes/Docker deployments with per-container /tmp and horizontal scaling; small tmpfs at TMPDIR aggressively cleaning files; file upload with EXIF stripping on slow disks where streams and cleanup race.

Related errors


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