Skip to content

Fix crash restoring a session serialized without undo history#5989

Open
xyos wants to merge 1 commit into
ajaxorg:masterfrom
xyos:fix-undo-history-restore
Open

Fix crash restoring a session serialized without undo history#5989
xyos wants to merge 1 commit into
ajaxorg:masterfrom
xyos:fix-undo-history-restore

Conversation

@xyos

@xyos xyos commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Problem

Restoring a session with EditSession.fromJSON() crashes on the first subsequent edit when the serialized session was using the default no-op undo manager:

Uncaught TypeError: Cannot set properties of undefined (setting 'length')
    at UndoManager.add (undomanager.js:45:58)
    at EditSession.onChange (edit_session.js:303:31)

EditSession.toJSON() serializes the undo manager under history; a session that never had a real UndoManager attached serializes it as {}. On restore, fromJSON then does:

undoManager.$undoStack = session.history.$undoStack; // undefined
undoManager.$redoStack = session.history.$redoStack; // undefined

clobbering the arrays the UndoManager constructor just created, so the first UndoManager.add() throws at this.$redoStack.length = 0.

Repro

var session = new EditSession("hello");            // default no-op undo manager
var restored = EditSession.fromJSON(JSON.stringify(session.toJSON()));
restored.insert({row: 0, column: 0}, "x");          // TypeError

This is hit in practice by the kitchen-sink demo, which persists the session to localStorage on unload and restores it via fromJSON on the next load — after which every keystroke/paste throws. Regression from the history serialization changes in #5920.

Fix

  • EditSession.fromJSON: tolerate a missing/empty history object and default $undoStack/$redoStack to [], mark/rev to 0.
  • UndoManager.fromJSON: guard against null/partial input the same way.
  • Regression test: round-trip a session without undo history and edit it.

Round-tripping a session with real history is unaffected (covered by the existing JSON serialization preserves undo/redo history test).

Open kitchen-sink @ ae482be47cbf147e7a550f1efc3487e0928f847a

EditSession.toJSON serializes the undo manager; sessions using the
default no-op undo manager serialize history as {}. fromJSON then set
UndoManager.$undoStack/$redoStack to undefined, so the first edit after
restore crashed in UndoManager.add with
'Cannot set properties of undefined (setting length)'.
Hit in kitchen-sink, which persists the session to localStorage on
unload and restores it on load (also reproducible on master).

Default missing history fields in EditSession.fromJSON and guard
UndoManager.fromJSON against null/partial input.
@codecov

codecov Bot commented Jul 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.74%. Comparing base (f82010e) to head (ae482be).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #5989      +/-   ##
==========================================
+ Coverage   93.73%   93.74%   +0.01%     
==========================================
  Files         641      641              
  Lines      138167   138182      +15     
  Branches    14561    14559       -2     
==========================================
+ Hits       129510   129539      +29     
+ Misses       8657     8643      -14     
Flag Coverage Δ
unittests 93.74% <100.00%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant