n8n-io/n8n · warning · BadRequestError

Content not viewable

Error message

Content not viewable

What it means

BadRequestError (HTTP 400) 'Content not viewable' thrown at binary-data.controller.ts:89 when `action === 'view'` and the resolved MIME type is missing or not in `ViewableMimeTypes`. Viewable set: application/json; audio/{mpeg,ogg,wav}; image/{bmp,gif,jpeg,jpg,png,tiff,webp}; text/{css,csv,markdown,plain}; video/{mp4,ogg,webm}. HTML, SVG, and PDF are intentionally excluded (XSS / code-exec risk).

Source

Thrown at packages/cli/src/controllers/binary-data.controller.ts:89

		}
	}

	private async setContentHeaders(
		binaryDataId: string,
		action: 'view' | 'download',
		res: Response,
		fileName?: string,
		mimeType?: string,
	) {
		try {
			const metadata = await this.binaryDataService.getMetadata(binaryDataId);
			fileName = metadata.fileName ?? fileName;
			mimeType = metadata.mimeType ?? mimeType;
			res.setHeader('Content-Length', metadata.fileSize);
		} catch {}

		if (action === 'view' && (!mimeType || !ViewableMimeTypes.includes(mimeType.toLowerCase()))) {
			throw new BadRequestError('Content not viewable');
		}

		if (mimeType) {
			res.setHeader('Content-Type', mimeType);
		}

		res.setHeader('Content-Security-Policy', getHtmlSandboxCSP());

		if (action === 'download') {
			if (fileName) {
				const encodedFilename = encodeURIComponent(fileName);
				res.setHeader('Content-Disposition', `attachment; filename="${encodedFilename}"`);
			} else {
				res.setHeader('Content-Disposition', 'attachment');
			}
		}
	}
}

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Use `action=download` instead of `view` for non-viewable MIME types.
  2. If the type should be viewable, set the correct `mimeType` query param or fix the binary metadata at write time.
  3. Never request `view` for HTML/SVG/PDF — the allowlist will refuse by design.

Example fix

// before
GET /binary-data?id=filesystem:report.html&action=view
// 400 Content not viewable

// after
GET /binary-data?id=filesystem:report.html&action=download
Defensive patterns

Strategy: validation

Validate before calling

const VIEWABLE = ['application/json','audio/mpeg','audio/ogg','audio/wav','image/bmp','image/gif','image/jpeg','image/jpg','image/png','image/tiff','image/webp','text/css','text/csv','text/markdown','text/plain','video/mp4','video/ogg','video/webm'];
function canView(mimeType?: string) {
  return !!mimeType && VIEWABLE.includes(mimeType.toLowerCase());
}
// action = canView(mt) ? 'view' : 'download'

Type guard

const VIEWABLE = ['application/json','audio/mpeg','audio/ogg','audio/wav','image/bmp','image/gif','image/jpeg','image/jpg','image/png','image/tiff','image/webp','text/css','text/csv','text/markdown','text/plain','video/mp4','video/ogg','video/webm'] as const;
const isViewable = (m?: string): m is string => !!m && (VIEWABLE as readonly string[]).includes(m.toLowerCase());

Try / catch

try { await get(req); } catch (e) { if (e instanceof BadRequestError && /not viewable/.test(e.message)) {/* fall back to download */} }

Prevention

When it happens

Trigger: Calling `GET /binary-data?id=...&action=view` on a binary whose MIME is `text/html`, `image/svg+xml`, `application/pdf`, an unknown type, or where no MIME is resolvable from metadata or query.

Common situations: Trying to inline-preview HTML/SVG/PDF outputs; attachments with missing/incorrect `mimeType`; frontend defaulting to `view` for unsafe types.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/415fc2b80c77406d. Report an issue: GitHub.