denoland/deno · error · ERR_INVALID_ARG_TYPE
ERR_INVALID_ARG_TYPE
ERR_INVALID_ARG_TYPE
Error message
ERR_INVALID_ARG_TYPE("historySize", "number", historySize) What it means
options.historySize of readline.createInterface (the max number of retained history lines, default 30) must be a number when provided. A string, boolean, null, or object throws ERR_INVALID_ARG_TYPE('historySize', 'number'). undefined falls back to the default, and NaN numbers are handled by the separate range check that follows.
Source
Thrown at ext/node/polyfills/internal/readline/interface.mjs:239
input = input.input;
}
if (completer !== undefined && typeof completer !== "function") {
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;View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Convert numeric strings at the boundary: Number(options.historySize)
- Validate config once: typeof cfg.historySize === 'number' or coerce and default
- Omit the option to accept the default 30
Example fix
// before
createInterface({ input, output, historySize: process.env.HIST_SIZE }); // string
// after
createInterface({ input, output, historySize: Number(process.env.HIST_SIZE) || 30 }); Defensive patterns
Strategy: type-guard
Validate before calling
function readHistorySize(cfg: Record<string, unknown>): number | undefined {
const n = Number(cfg.historySize);
return Number.isFinite(n) && n >= 0 ? n : undefined;
}
readline.createInterface({ input, output, historySize: readHistorySize(cfg) }); Type guard
const isHistorySize = (v: unknown): v is number => typeof v === 'number' && !Number.isNaN(v) && v >= 0;
Try / catch
try {
rl = readline.createInterface({ input, historySize: size as number });
} catch (err) {
if (err?.code === 'ERR_INVALID_ARG_TYPE' && /historySize/.test(err.message)) {
rl = readline.createInterface({ input, historySize: Number(size) || 30 });
} else throw err;
} Prevention
- Number()-convert historySize from env/JSON config at load time
- Omit the option when the source is untrusted; default 30 applies
When it happens
Trigger: createInterface({ historySize: '100' }) from parsed config/CLI args; historySize: parseInt(input) where parseInt returned NaN is caught here only if the argument was not a number type at all — strings are the common case; passing the whole options object as historySize.
Common situations: REPL tool configuration read from JSON/env where every value is a string; merging user preferences objects that carry stringified sizes.
Understand the failure class
Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.
Related errors
- ERR_OUT_OF_RANGE
- ERR_MISSING_ARGS
- No callback function supplied
- ERR_INVALID_ARG_TYPE
- No callback function supplied
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/35b0a4298b995a7a.
Report an issue: GitHub.