n8n-io/n8n · error
xlsx "${attachment.fileName}" has no sheets.
Error message
xlsx "${attachment.fileName}" has no sheets. What it means
Thrown by extractXlsxAsRows (xlsx-parser.ts:39-42) when workbook.SheetNames is empty or its first entry is falsy. SheetJS parsed the zip successfully but found no sheets at all, so there is nothing to extract. This is a content-level rejection that happens after the parse try/catch and before sheet_to_json.
Source
Thrown at packages/@n8n/instance-ai/src/parsers/xlsx-parser.ts:41
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 types
// (numbers, booleans) survive and we share row/column budget logic.
const jsonAttachment: AttachmentInfo = {
data: Buffer.from(JSON.stringify(json), 'utf-8').toString('base64'),
mimeType: 'application/json',
fileName: attachment.fileName,View on GitHub (pinned to 5ac6606e81)
Solutions
- Open the workbook and confirm at least one sheet exists; re-save.
- Regenerate the file from the source pipeline with the intended sheet.
- If the file is a template, fill it before attaching.
- Attach a different, non-empty file.
Example fix
// before: attach 'empty.xlsx' with 0 sheets // after: add at least one sheet with data, re-save, attach
Defensive patterns
Strategy: try-catch
Validate before calling
// After parsing the workbook yourself (or pre-check):
// import * as XLSX from '@e965/xlsx';
// const wb = XLSX.read(decoded, { type: 'buffer' });
// if (!wb.SheetNames.length) throw new Error('workbook has no sheets'); Type guard
function workbookHasSheets(wb: { SheetNames: string[] }): boolean {
return Array.isArray(wb.SheetNames) && wb.SheetNames.length > 0;
} Try / catch
try { return await extractXlsxAsRows(attachment, idx, input); }
catch (e) {
if (e instanceof Error && /has no sheets$/.test(e.message)) {
// ask for a workbook with at least one sheet
}
throw e;
} Prevention
- Confirm the source workbook has data before exporting.
- Avoid attaching template stubs with no sheets.
- Validate with SheetJS in a pre-check if untrusted.
When it happens
Trigger: A valid OOXML zip with an empty workbook part; a workbook whose sheets were all deleted; a workbook where SheetNames is present but empty. The XLSX.read call itself succeeded.
Common situations: User deleted all sheets before saving; a template/export pipeline emitted a workbook stub with no sheets; a programmatic generator wrote the workbook structure but no sheet parts.
Related errors
- xlsx "${attachment.fileName}" sheet "${firstSheetName}" is e
- Nested ${Array.isArray(value) ? 'array' : 'object'} found at
- Unsupported format for "${attachment.fileName}" (${attachmen
- Unsupported attachment type: ${summary}
- Attachment exceeds maximum size of 10.0 MB (got ${formatMB(a
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/6a7b0725bc38569b.
Report an issue: GitHub.