denoland/deno · error · ERR_OUT_OF_RANGE

ERR_OUT_OF_RANGE

ERR_OUT_OF_RANGE

Error message

The value of "historySize" is out of range. It must be >= 0. Received ${historySize}

What it means

After the type check, historySize must be a non-negative, non-NaN number; NaN or any value < 0 throws ERR_OUT_OF_RANGE('historySize', '>= 0'). Zero is legal (disables history). This guards the ring buffer that stores previous input lines.

Source

Thrown at ext/node/polyfills/internal/readline/interface.mjs:243

    throw new ERR_INVALID_ARG_VALUE("completer", completer);
  }

  if (history === undefined) {
    history = [];
  } else {
    validateArray(history, "history");
  }

  if (historySize === undefined) {
    historySize = kHistorySize;
  }

  if (typeof historySize !== "number") {
    throw new ERR_INVALID_ARG_TYPE("historySize", "number", historySize);
  }

  if (NumberIsNaN(historySize) || historySize < 0) {
    throw new ERR_OUT_OF_RANGE("historySize", ">= 0", historySize);
  }

  // Backwards compat; check the isTTY prop of the output stream
  //  when `terminal` was not specified
  if (terminal === undefined && !(output === null || output === undefined)) {
    terminal = !!output.isTTY;
  }

  const self = this;

  this.line = "";
  this[kSubstringSearch] = null;
  this.output = output;
  this.input = input;
  this.history = history;
  this.historySize = historySize;
  this.removeHistoryDuplicates = !!removeHistoryDuplicates;
  this.crlfDelay = crlfDelay

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Treat 'unlimited' as a large finite number or omit the option, never -1
  2. Clamp: Math.max(0, Number(cfg.historySize) || 0)
  3. Check Number.isFinite before passing

Example fix

// before
createInterface({ input, output, historySize: cfg.unlimited ? -1 : 30 });

// after
createInterface({ input, output, historySize: cfg.unlimited ? 10000 : 30 });
Defensive patterns

Strategy: validation

Validate before calling

const historySize = Math.max(0, Number(cfg.historySize) || 30);
readline.createInterface({ input, output, historySize });

Type guard

const isNonNegativeHistorySize = (v: unknown): v is number =>
  typeof v === 'number' && Number.isFinite(v) && v >= 0;

Try / catch

try {
  rl = readline.createInterface({ input, historySize: size });
} catch (err) {
  if (err?.code === 'ERR_OUT_OF_RANGE' && /historySize/.test(err.message)) {
    rl = readline.createInterface({ input, historySize: 0 });
  } else throw err;
}

Prevention

When it happens

Trigger: createInterface({ historySize: -1 }); historySize: NaN from Number('unlimited') or parseInt failures that still produce NaN (a number type); arithmetic like size - offset going negative.

Common situations: Computing history size from a subtraction or percentage that can go below zero; Number(...) of a non-numeric env value producing NaN; sentinel values like -1 meaning 'unlimited' being forwarded directly.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/48906c35370388c4. Report an issue: GitHub.