mobxjs / mobx-state-tree

Full-featured reactive state management without the boilerplate

Home Page:https://mobx-state-tree.js.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Unexpected error "Сannot finalize the creation of a node that is already dead" while applying snapshot

dfilatov opened this issue · comments

Bug report

  • I've checked documentation and searched for existing issues and discussions
  • I've made sure my project is based on the latest MST version
  • Fork this code sandbox or another minimal reproduction.

Sandbox link or minimal reproduction code

import { types, applySnapshot } from 'mobx-state-tree';

const Model = types.array(
    types.model({
        b: types.string,
        c: types.optional(
            types.model({
                d: types.snapshotProcessor(
                    types.model({ e: '' }),
                    {
                        preProcessor(e: string) {
                            return { e };
                        },

                        postProcessor(snapshot) {
                            return snapshot.e;
                        }
                    }
                )
            }),
            { d: '' }
        )
    })
);

const m = Model.create([{ b: 'b' }]);

applySnapshot(m, []);

Describe the expected behavior

Should work without any errors

Describe the observed behavior

Error: [mobx-state-tree] assertion failed: cannot finalize the creation of a node that is already dead

I think this may be a docs and TypeScript issue. You're calling preProcessor and postProcessor, but the types.snapshotProcessor actually wants preProcess and postProcess.

You can see it working here: https://codesandbox.io/p/sandbox/issue-2136-7hpyd2?file=%2Fsrc%2Findex.ts%3A21%2C3

But there's TypeScript errors on those actions.

Here's the working code for posterity:

import { types, applySnapshot } from "mobx-state-tree";

const Model = types.array(
  types.model({
    b: types.string,
    c: types.optional(
      types.model({
        d: types.snapshotProcessor(types.model({ e: "" }), {
          // TypeScript errors here, but I think that's incorrect
          preProcess(snapshot: { e: string }) {
            return { e: snapshot.e };
          },

         // TypeScript errors here, but I think that's incorrect
          postProcess(snapshot: { e: string }) {
            return snapshot.e;
          },
        }),
      }),
      { d: { e: "e" } }
    ),
  })
);

const m = Model.create([{ b: "b" }]);

applySnapshot(m, []);

I'll tag this, and please accept our apologies for the bug! We'll close this issue when we fix the types, but please let me know if I've missed anything else.

Ah, my bad! I had a false positive, was just getting those errors to go away.

There is a documentation issue. We call it preProcess and postProcess here: https://mobx-state-tree.js.org/overview/hooks#snapshot-processing-hooks. That's what threw me and got me here.

I'll remove the TypeScript label here. I've been messing around with the code and I think this is coming from postProcessor. If you remove that action, the error goes away.

Seems to be related to applying the snapshot as an empty array. I can get the processed snapshot, modify it in place, and apply it correctly:

import { types, applySnapshot, getSnapshot } from "mobx-state-tree";

const Model = types.array(
  types.model({
    b: types.string,
    c: types.optional(
      types.model({
        d: types.snapshotProcessor(types.model({ e: "" }), {
          preProcessor(snapshot: { e: string }) {
            return { e: snapshot.e };
          },

          postProcessor(snapshot: { e: string }, node) {
            return {
              ...snapshot,
              e: "modified",
            };
          },
        }),
      }),
      { d: { e: "e" } }
    ),
  })
);

const m = Model.create([{ b: "b" }]);

const snapshot = getSnapshot(m);

console.log("snapshot", snapshot);

const modifiedSnapshot = [...snapshot];

console.log("modifiedSnapshot", modifiedSnapshot);

modifiedSnapshot[0].c.d.e = "modifiedAgain";

applySnapshot(m, modifiedSnapshot);

console.log("snapshot one last time", getSnapshot(m));

Updated example there:

https://codesandbox.io/p/sandbox/issue-2136-7hpyd2?file=%2Fsrc%2Findex.ts%3A41%2C1

But if you try to apply as an empty array, the error comes back.

Sorry, I can't open your example:
image

Whoops, getting used to the new CodeSandbox tools. This should work: https://codesandbox.io/p/sandbox/issue-2136-7hpyd2?file=%2Fsrc%2Findex.ts%3A41%2C1

I've got some pass-by-reference errors in there, but I gotta run at the moment so I can revisit this later. Sorry 'bout that!

It's not related with an empty array, following code throws the same error:

const Model = types.array(
      types.model({
        b: types.string,
        c: types.optional(
          types.model({
            d: types.snapshotProcessor(types.model({ e: '' }), {
              preProcessor(e: string) {
                return { e };
              },

              postProcessor(snapshot) {
                return snapshot.e;
              }
            })
          }),
          { d: 'e' }
        )
      })
    );

    const m = Model.create([{ b: 'b' }, { b: 'bb' }]);

    applySnapshot(m, [{ b: 'b' }]); // error

Interestingly, if I remove types.optional in the middle then everything works:

    const Model = types.array(
      types.model({
        b: types.string,
        c:
          types.model({
            d: types.snapshotProcessor(types.model({ e: '' }), {
              preProcessor(e: string) {
                return { e };
              },

              postProcessor(snapshot) {
                return snapshot.e;
              }
            })
          })
      })
    );

    const m = Model.create([{ b: 'b', c: { d: '' } }, { b: 'bb', c: { d: '' } }]);

    applySnapshot(m, [{ b: 'b', c: { d: '' } }]);

Interesting. Maybe types.optional is having trouble instantiating the default value as a snapshotProcessor.

Hopefully it's just this: #2137

Once we get a test in there I can merge and deploy a patch, probably early this week.

Unfortunately, no (
It just fixes import but exception will be thrown anyway, I've checked it.

Ah dang. Do you have the full text of the exception with that patched? That might be helpful

Ah dang. Do you have the full text of the exception with that patched? That might be helpful

image

Thank you! I'll see if I can get anyone to investigate. If not, I can at some point in the coming weeks. Would welcome a PR if you trace the error on your own as well. Apologies for the inconvenience!

Hi, @coolsoftwaretyler! Is there any progress?

Sorry, not yet! Haven't had anyone volunteer to work on it.