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
- Identify the errno in the logged error object: ENOENT is harmless, EACCES/EROFS are configuration problems
- For EACCES/EROFS, point TMPDIR to a writable directory owned by the Rocket.Chat process and mount it consistently across replicas
- ENOENT: look for duplicate cleanup calls for the same upload and deduplicate them
- 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
- Mount a writable, shared TMPDIR with consistent ownership on all replicas
- Never call cleanup twice for the same temp path — track the file lifecycle per upload
- Alert on temp-dir disk usage growth to catch silently failing cleanups early
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
- The environmental variable "${envVarName}" is not readable.
- auth option should be of the form "username:password"
- Unknown error
- Missing user to perform the upload operation
- error-no-file-uploaded
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/92a429ebd036e114.
Report an issue: GitHub.