n8n-io/n8n · error

Attachment exceeds maximum size of 10.0 MB (got ${formatMB(a

Error message

Attachment exceeds maximum size of 10.0 MB (got ${formatMB(actualBytes)})

What it means

Thrown by extractXlsxAsRows (xlsx-parser.ts:24-25) when the decoded .xlsx byte length exceeds MAX_DECODED_SIZE_BYTES (10MB). This is the xlsx-specific twin of error 503; the decoded (not base64) size is measured before SheetJS ever opens the workbook. A subsequent assertOoxmlWithinBounds check guards uncompressed (decompression-bomb) size separately.

Source

Thrown at packages/@n8n/instance-ai/src/parsers/xlsx-parser.ts:25

	type ParseFileInput,
	type ParseFileOutput,
} from './structured-file-parser';

/**
 * Extracts the first sheet of an `.xlsx` workbook as tabular rows.
 *
 * Strategy: convert the sheet to CSV text via SheetJS, then route through the
 * existing `parseStructuredFile` so column normalization, type inference, and
 * truncation budgets stay in one place.
 */
export async function extractXlsxAsRows(
	attachment: AttachmentInfo,
	attachmentIndex: number,
	input: ParseFileInput,
): Promise<ParseFileOutput> {
	const decoded = Buffer.from(attachment.data, 'base64');
	if (decoded.length > MAX_DECODED_SIZE_BYTES) {
		throw new Error(formatSizeLimitMessage(decoded.length));
	}
	assertOoxmlWithinBounds(decoded, attachment.fileName);

	const XLSX = await import('@e965/xlsx');

	let workbook: ReturnType<typeof XLSX.read>;
	try {
		workbook = XLSX.read(decoded, { type: 'buffer' });
	} catch (error) {
		const message = error instanceof Error ? error.message : 'unknown error';
		throw new Error(`Failed to parse xlsx "${attachment.fileName}": ${message}`);
	}

	const firstSheetName = workbook.SheetNames[0];
	if (!firstSheetName) {
		throw new Error(`xlsx "${attachment.fileName}" has no sheets.`);
	}

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Strip embedded media, unused sheets, and styling from the workbook.
  2. Keep only the sheet the task needs and save as a lean .xlsx.
  3. Convert the relevant sheet to CSV and attach as text/csv if a spreadsheet is not required.
  4. Sample/filter rows before exporting.

Example fix

// before: attach a 13MB .xlsx with embedded charts
// after:  export the target sheet as CSV (~1MB) and attach as text/csv
Defensive patterns

Strategy: validation

Validate before calling

import { MAX_DECODED_SIZE_BYTES } from './structured-file-parser';
const decoded = Buffer.from(attachment.data, 'base64');
if (decoded.length > MAX_DECODED_SIZE_BYTES) {
  throw new Error(`xlsx too large after decode: ${decoded.length} bytes`);
}

Type guard

function xlsxWithinDecodedLimit(base64: string, limit = MAX_DECODED_SIZE_BYTES): boolean {
  return Buffer.byteLength(base64, 'base64') <= limit;
}

Try / catch

try { return await extractXlsxAsRows(attachment, idx, input); }
catch (e) {
  if (e instanceof Error && e.message.startsWith('Attachment exceeds')) {
    // strip embedded media / unused sheets, re-save, retry
  }
  throw e;
}

Prevention

When it happens

Trigger: An .xlsx attachment whose decoded bytes > 10MB. Because .xlsx is a ZIP, the base64 string can be considerably smaller than the decoded buffer.

Common situations: A workbook with embedded images, many sheets, or large cached formula values; a file that is mostly formatting overhead; user assumes the base64 length is the enforced limit.

Related errors


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