n8n-io/n8n · error
Failed to parse xlsx "${attachment.fileName}": ${message}
Error message
Failed to parse xlsx "${attachment.fileName}": ${message} What it means
Thrown by extractXlsxAsRows (xlsx-parser.ts:34-37) when SheetJS XLSX.read throws while parsing the decoded buffer. The original error message is interpolated into the thrown Error so the underlying cause (corrupt zip, unsupported format, encryption) is visible. This is a parser-level failure distinct from the structural checks that follow.
Source
Thrown at packages/@n8n/instance-ai/src/parsers/xlsx-parser.ts:36
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.`);
}
const sheet = workbook.Sheets[firstSheetName];
const json = XLSX.utils.sheet_to_json<Record<string, unknown>>(sheet, {
blankrows: false,
defval: null,
});
if (json.length === 0) {
throw new Error(`xlsx "${attachment.fileName}" sheet "${firstSheetName}" is empty.`);
}
// Round-trip through the JSON path of parseStructuredFile so typesView on GitHub (pinned to 5ac6606e81)
Solutions
- Re-save the workbook as a standard .xlsx from Excel/Google Sheets/LibreOffice.
- Remove password protection before attaching.
- Verify the file is a valid ZIP (e.g. check the PK header) before attaching.
- If the source is legacy .xls, convert to .xlsx or to CSV first.
Example fix
// before: attach legacy 'data.xls' renamed to 'data.xlsx' // after: open in Excel, 'Save As -> .xlsx', then attach
Defensive patterns
Strategy: try-catch
Validate before calling
// Cheap structural check before calling extractXlsxAsRows
const decoded = Buffer.from(attachment.data, 'base64');
const isZip = decoded.length >= 4 && decoded[0] === 0x50 && decoded[1] === 0x4b;
if (!isZip) throw new Error('Not a valid xlsx (ZIP) container'); Type guard
function looksLikeXlsxZip(buf: Buffer): boolean {
return buf.length >= 4 && buf[0] === 0x50 && buf[1] === 0x4b && (buf[2] === 0x03 || buf[2] === 0x05 || buf[2] === 0x07);
} Try / catch
try { return await extractXlsxAsRows(attachment, idx, input); }
catch (e) {
if (e instanceof Error && e.message.startsWith('Failed to parse xlsx')) {
// prompt user to re-save as standard .xlsx; do not retry the same bytes
}
throw e;
} Prevention
- Re-save .xlsx from a conformant application before attaching.
- Remove password protection from workbooks.
- Reject legacy .xls by mime type (application/vnd.ms-excel) up front.
When it happens
Trigger: A file labeled .xlsx that is not a valid OOXML zip: a legacy .xls saved with the wrong extension, a password-protected workbook, a truncated download, or a corrupted archive. Also triggered if SheetJS encounters an unsupported feature it cannot decode.
Common situations: User renames .xls to .xlsx; file was downloaded incompletely; workbook is encrypted; a third-party tool produced a non-conformant OOXML zip; version skew between SheetJS (@e965/xlsx) and the producing application.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Attachment exceeds maximum size of 10.0 MB (got ${formatMB(a
- xlsx "${attachment.fileName}" has no sheets.
- xlsx "${attachment.fileName}" sheet "${firstSheetName}" is e
- Dangerous key "${dangerousKey}" found in JSON data
- Nested ${Array.isArray(value) ? 'array' : 'object'} found at
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/ec117fb76e7bd5c1.
Report an issue: GitHub.