RocketChat/Rocket.Chat · error

Unknown error

Error message

Unknown error

What it means

UploadsBridge.getBuffer validates that FileUpload.getBuffer returns a Node Buffer; anything else (undefined, null, a non-Buffer stream result) collapses into the opaque 'Unknown error'. The real cause is the file store failing to produce the file's bytes — the store returned nothing rather than throwing, e.g. the file is missing from GridFS/the filesystem/S3.

Solutions

  1. Verify the file actually exists in the store (S3 bucket / GridFS collection / Uploads directory) and the store backend is reachable.
  2. Check the FileUpload settings (storage type, path, bucket, region, credentials) in the admin UI.
  3. If the bytes are gone, treat reads of that upload id as permanently failed and re-upload the file.
  4. Server-side improvement: wrap the store read so the underlying store error is surfaced instead of 'Unknown error'.

Example fix

// before
const buffer = await getBuffer(upload, appId); // throws 'Unknown error'

// after - wrap and contextualize
try {
  const buffer = await getBuffer(upload, appId);
} catch (err) {
  throw new Error(`Could not load file '${upload.name}' (${upload.id}) from the file store`, { cause: err });
}
Defensive patterns

Strategy: try-catch

Type guard

const isBuffer = (b: unknown): b is Buffer => Buffer.isBuffer(b);

Try / catch

Catch, then wrap with upload id/name context and fail that single file; do not retry — missing store bytes will not reappear.

Prevention

When it happens

Trigger: App reads an upload whose bytes are gone from the store (GridFS document deleted, file removed from disk, S3 object missing); S3-compatible store misconfiguration (wrong bucket/credentials/endpoint) making the read return empty; upload metadata record exists but the file itself is inconsistent.

Common situations: Database restored without the file store; S3 credential rotation; filesystem store path changed; the file was deleted while the app still held the IUpload object.

Related errors


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

Appendix: source

Thrown at apps/meteor/app/apps/server/bridges/uploads.ts:39

	}

	protected async getById(id: string, appId: string): Promise<IUpload> {
		this.orch.debugLog(`The App ${appId} is getting the upload: "${id}"`);

		// #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed.
		const promise: Promise<IUpload | undefined> = this.orch.getConverters()?.get('uploads').convertById(id);
		return promise as Promise<IUpload>;
	}

	protected async getBuffer(upload: IUpload, appId: string): Promise<Buffer> {
		this.orch.debugLog(`The App ${appId} is getting the upload: "${upload.id}"`);

		const rocketChatUpload = this.orch.getConverters()?.get('uploads').convertToRocketChat(upload);

		const result = await FileUpload.getBuffer(rocketChatUpload);

		if (!(result instanceof Buffer)) {
			throw new Error('Unknown error');
		}

		return result;
	}

	protected async createUpload(details: IUploadDetails, buffer: Buffer, appId: string): Promise<IUpload> {
		this.orch.debugLog(`The App ${appId} is creating an upload "${details.name}"`);

		if (!details.userId && !details.visitorToken) {
			throw new Error('Missing user to perform the upload operation');
		}

		const fileStore = FileUpload.getStore('Uploads');

		details.type = determineFileType(buffer, details.name);

		const uploadedFile = await fileStore.insert(getUploadDetails(details), buffer);
		this.orch.debugLog(`The App ${appId} has created an upload`, uploadedFile);

View on GitHub (pinned to b2c16d5842)