Skip to content

Error Map maximum size exceeded when loading a 30-milion-cell worksheet #1602

@sequba

Description

@sequba

Description

When loading a large Excel file into HyperFormula, the dependency graph's internal Map exceeds JavaScript's maximum Map size (~16.7 million entries), causing a crash.

node_modules/hyperformula/commonjs/DependencyGraph/Graph.js:126
    this.nodesIds.set(node, newId);
                  ^

RangeError: Map maximum size exceeded
    at Map.set (<anonymous>)
    at Graph.addNodeAndReturnId (/node_modules/hyperformula/commonjs/DependencyGraph/Graph.js:126:19)
    at DependencyGraph.exchangeOrAddGraphNode (/node_modules/hyperformula/commonjs/DependencyGraph/DependencyGraph.js:837:18)
    at DependencyGraph.setValueToCell (/node_modules/hyperformula/commonjs/DependencyGraph/DependencyGraph.js:164:12)
    at Operations.setValueToCell (/node_modules/hyperformula/commonjs/Operations.js:572:47)
    at Operations.setCellContent (/node_modules/hyperformula/commonjs/Operations.js:523:12)
    at CrudOperations.setCellContents (/node_modules/hyperformula/commonjs/CrudOperations.js:197:44)
    at HyperFormula.setCellContents (/node_modules/hyperformula/commonjs/HyperFormula.js:1148:26)
    at run (/read-excel-file.js:21:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:105:5)

Node.js v22.21.1

Discovered and reported by @Krizz in #1597

Demo

  1. Download a dataset from https://data.cityofnewyork.us/Environment/2015-Street-Tree-Census-Tree-Data/uvpi-gqnh/about_data (click Export->XLSX)

  2. Run

const ExcelJS = require('exceljs');
const { HyperFormula } = require('hyperformula');

async function run(filename) {
  const hf = HyperFormula.buildEmpty({
    licenseKey: 'gpl-v3',
    maxRows: 1000000,
  });

  const workbookReader = new ExcelJS.stream.xlsx.WorkbookReader(filename);

  for await (const worksheetReader of workbookReader) {
    const sheetName = worksheetReader.name;
    const actualSheetName = hf.addSheet(sheetName);
    const sheetId = hf.getSheetId(actualSheetName);

    let rowIndex = 0;
    for await (const row of worksheetReader) {
      const rowData = extractRowData(row);
      if (rowData.length > 0) {
        hf.setCellContents({ sheet: sheetId, row: rowIndex, col: 0 }, [rowData]);
      }
      rowIndex++;
    }
  }

  console.log(hf.getSheetNames());
}

/**
 * Extracts cell values from a streaming row object.
 * @param {ExcelJS.Row} row - The row from ExcelJS streaming reader
 * @returns {Array} Array of cell values (formulas prefixed with '=')
 */
function extractRowData(row) {
  const rowData = [];

  row.eachCell({ includeEmpty: true }, (cell, colNumber) => {
    // Expand array to fill gaps (ExcelJS skips empty cells by default)
    while (rowData.length < colNumber - 1) {
      rowData.push(null);
    }
    const cellData = cell.formula ? `=${cell.formula}` : cell.value;
    rowData.push(cellData);
  });

  return rowData;
}

HyperFormula version

3.1.1

Your environment

node + exceljs lib

Metadata

Metadata

Labels

BugSomething isn't workingImpact: LowPerformanceIssues related to the performance

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions