#3074·exceljs

[BUG] Streaming WorksheetReader blanks a formula cell whose cached result is an error (t="e")

Author: vzakharovCreated Aug 24, 2026Updated Aug 24, 2026

Description

stream.xlsx.WorkbookReader coerces a formula cell's cached result with parseFloat for every type except t="str". An error result (t="e") therefore parses to NaN, and the cell reads back blank instead of carrying the error.

The non-streaming reader gets this right — lib/xlsx/xform/sheet/cell-xform.js handles t="e" explicitly — so the two readers disagree on the same file.

Steps to reproduce

javascript
const ExcelJS = require('exceljs');

const wb = new ExcelJS.Workbook();
wb.addWorksheet('S').getCell('A1').value = {
formula: 'C1/D1',
result: {error: '#REF!'},
};
const buf = await wb.xlsx.writeBuffer(); // <c r="A1" t="e"><f>C1/D1</f><v>#REF!</v></c>

// non-streaming: { formula: 'C1/D1', result: { error: '#REF!' } }
const round = new ExcelJS.Workbook();
await round.xlsx.load(buf);
console.log(round.getWorksheet('S').getCell('A1').value);

// streaming: { formula: 'C1/D1', result: NaN }
const reader = new ExcelJS.stream.xlsx.WorkbookReader(require('stream').Readable.from(buf), {
worksheets: 'emit', sharedStrings: 'cache', styles: 'cache',
});
for await (const ws of reader) {
for await (const row of ws) console.log(row.getCell(1).value);
}

Expected

{ formula: 'C1/D1', result: { error: '#REF!' } } from both readers.

Actual

Streaming yields { formula: 'C1/D1', result: NaN }, which renders as an empty cell.

Suggested fix

lib/stream/xlsx/worksheet-reader.js, in the c.f branch:

diff
if (c.v) {
-   if (c.t === 'str') {
+   if (c.t === 'e') {
+     cellValue.result = {error: c.v.text};
+   } else if (c.t === 'str') {
cellValue.result = utils.xmlDecode(c.v.text);
} else {
cellValue.result = parseFloat(c.v.text);

Version

exceljs 4.4.0, Node 24.