Skip to content

readline: fix crash when navigating wrapped multiline history - #65610

Open
piyushrajyadav wants to merge 1 commit into
nodejs:mainfrom
piyushrajyadav:fix-readline-multiline-crash
Open

readline: fix crash when navigating wrapped multiline history#65610
piyushrajyadav wants to merge 1 commit into
nodejs:mainfrom
piyushrajyadav:fix-readline-multiline-crash

Conversation

@piyushrajyadav

@piyushrajyadav piyushrajyadav commented Aug 28, 2026

Copy link
Copy Markdown

Fixes: #59431

Description

When navigating multiline history in readline / REPL using the <UP> / <DOWN> arrow keys, [kMultilineMove] previously used this.getCursorPos() to determine the row index of the cursor.

However, getCursorPos() returns the visual/display row coordinates on the terminal screen (which counts visual line wraps when a logical line exceeds this.columns). In contrast, splitLines is the array of logical lines delimited by \n.

When an entry contained a logical line long enough to wrap across multiple terminal columns, cursorPos.rows exceeded splitLines.length - 1. As a result, splitLines[cursorPos.rows] resolved to undefined, throwing:

TypeError: Cannot read properties of undefined (reading 'length')
    at [_multilineMove] (node:internal/readline/interface:1088:36)
    at [_moveUpOrHistoryPrev] (node:internal/readline/interface:1145:27)

and terminating the REPL process.

This change:

  1. Adds getLogicalCursorPos() to lib/internal/readline/interface.js to compute the logical line index and column offset based on \n character positions in this.line.
  2. Updates [kMultilineMove], [kMoveUpOrHistoryPrev], and [kMoveDownOrHistoryNext] to use logical coordinates.
  3. Adds a regression test to test/parallel/test-readline-interface.js.

Verification

  • Verified regression test added in test/parallel/test-readline-interface.js.
  • Verified formatting, whitespace, and primordials usage (StringPrototypeLastIndexOf).

When navigating multiline history in readline/REPL with the UP/DOWN
arrow keys, [kMultilineMove] used getCursorPos() (which returns the
terminal screen's visual row and column index) to index into the
logical \n-delimited splitLines array.

When a logical line was long enough to wrap across multiple terminal
columns, cursorPos.rows exceeded splitLines.length - 1, causing
splitLines[cursorPos.rows] to be undefined and throwing:
  TypeError: Cannot read properties of undefined (reading 'length')

This commit adds getLogicalCursorPos() to compute the logical row and
column based on \n characters in this.line and uses it across
multiline history navigation.

Fixes: nodejs#59431
Signed-off-by: piyushrajyadav <piyushyadavrajyadav@gmail.com>
Assisted-by: Antigravity <antigravity@google.com>
@nodejs-github-bot nodejs-github-bot added needs-ci PRs that need a full CI run. readline Issues and PRs related to the built-in readline module. labels Aug 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-ci PRs that need a full CI run. readline Issues and PRs related to the built-in readline module.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Node repl crashes when trying to call back a large multiline item

2 participants