Skip to content

Commit 9d1f09c

Browse files
fix(ui): return wrapped history in redux-remember unserialize
We intermittently get an error like this: ``` TypeError: Cannot read properties of undefined (reading 'length') ``` This error is caused by a `redux-undo`-enhanced slice being rehydrated without the extra stuff it adds to the slice to make it undoable (e.g. an array of `past` states, the `present` state, array of `future` states, and some other metadata). `redux-undo` may need to check the length of the past/future arrays as part of its internal functionality. These keys don't exist so we get the error. I'm not sure _why_ they don't exist - my understanding of `redux-undo` is that it should be checking and wrapping the state w/ the history stuff automatically. Seems to be related to `redux-remember` - may be a race condition. The solution is to ensure we wrap rehydrated state for undoable slices as we rehydrate them. I discovered the solution while troubleshooting #8314 when the changes therein somehow triggered the issue to start occuring every time instead of rarely.
1 parent cacfb18 commit 9d1f09c

File tree

1 file changed

+12
-3
lines changed
  • invokeai/frontend/web/src/app/store

1 file changed

+12
-3
lines changed

invokeai/frontend/web/src/app/store/store.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import { diff } from 'jsondiffpatch';
3131
import dynamicMiddlewares from 'redux-dynamic-middlewares';
3232
import type { SerializeFunction, UnserializeFunction } from 'redux-remember';
3333
import { rememberEnhancer, rememberReducer } from 'redux-remember';
34-
import undoable from 'redux-undo';
34+
import undoable, { newHistory } from 'redux-undo';
3535
import { serializeError } from 'serialize-error';
3636
import { api } from 'services/api';
3737
import { authToastMiddleware } from 'services/api/authToastMiddleware';
@@ -118,6 +118,7 @@ const unserialize: UnserializeFunction = (data, key) => {
118118
if (!persistConfig) {
119119
throw new Error(`No persist config for slice "${key}"`);
120120
}
121+
let state;
121122
try {
122123
const { initialState, migrate } = persistConfig;
123124
const parsed = JSON.parse(data);
@@ -141,13 +142,21 @@ const unserialize: UnserializeFunction = (data, key) => {
141142
},
142143
`Rehydrated slice "${key}"`
143144
);
144-
return transformed;
145+
state = transformed;
145146
} catch (err) {
146147
log.warn(
147148
{ error: serializeError(err as Error) },
148149
`Error rehydrating slice "${key}", falling back to default initial state`
149150
);
150-
return persistConfig.initialState;
151+
state = persistConfig.initialState;
152+
}
153+
154+
// If the slice is undoable, we need to wrap it in a new history - only nodes and canvas are undoable at the moment.
155+
// TODO(psyche): make this automatic & remove the hard-coding for specific slices.
156+
if (key === nodesSlice.name || key === canvasSlice.name) {
157+
return newHistory([], state, []);
158+
} else {
159+
return state;
151160
}
152161
};
153162

0 commit comments

Comments
 (0)