TypeManager.TS icon indicating copy to clipboard operation
TypeManager.TS copied to clipboard

"Cannot define discriminant of polymorphic type" only after build.

Open Offlein opened this issue 3 months ago • 1 comments

Hello! Per a ticket I created last year, I've got a use-case of a single common codebase that I'm including from 3 different Vue frontend apps. I had issues with it being duplicated, and since working that out things have largely been good.

I'm about to do a large deploy, however, and I'm finding that in my Staging environment, my app is reliably failing in one of my Vue apps (call it my "Client App") with an error about "Cannot define discriminant of polymorphic type" on a ClientUser class that is a child of a User class in the shared library.

I would not have thought that I'd changed much in this "area" of my codebase, but maybe I did. Regardless, the issue was never noticed in my local dev environment. For some reason, in my local dev, the error was only triggered rarely, and if I refreshed it would frequently not recur. Which I guess sounds to me like some sort of race condition?

Regardless, if I sit refreshing in local dev, I could reliably make it occur. I had some difficulty understanding the meaning of the Discriminant/Discriminator documentation at first, but after a while I think I got it. Basically, if I have a parent class and a child class, when I deserialize I should have a string property (on the raw JSON being deserialized) called (by default) $type. And if that string equates to the class name ("ClientUser" vs "User" in my example), then TypeManager.TS can understand which class to deserialize into.

So: I made sure my backend is sending the relevant class names in a $type property. From that point on, I cannot recreate the issue in my local dev. If I undo that, they issue recurs. So that seemed like a full solution.

However, once I do a build and deploy for my Stage environment, the issue occurred reliably 100% of the time. Even with the backend sending a $type property.

After trying several things, I went through to all the relevant classes and I manually hardcoded both a discriminant: {-{...TheClassName...} and a discriminator: '$type' typeOption on the type decorator itself. Which I think should be the same as the defaults..?

But after deploying this, my app seems to work perfectly fine again in my Staging environment.

I cannot for the life of me understand what is going on. Part of me wonders if there is a[nother?] race condition maybe in the build process, such that it sometimes builds in a bad way and it sometimes doesn't, and I just happened to get lucky with this last build. But I really don't know.


I also, when having the error in Stage, set breakpoints in my Chrome Dev Tools. It was failing in this function, so I set them here: SerializerContext.prototype.definePolymorphicSerializerContextByDiscriminant = function (record) {. But the record[typeMetadata.discriminator] value in that function seemed to always be uglified such that I couldn't really understand what was going on.

I had the idea to throw a debugger; statement around that line in my local node_modules, but it never triggered. (I was putting it in @dipscope/type-manager/dist/es5/serializer-context.js line 350).

...My local Vite also doesn't seem to be writing its .map files to properly reference what's in node_modules for some reason, so that's possibly part of the issue. (...I wish there was some way I could easily just run my stage build in my local workflow, but that's got nothing to do with you!)

Thanks in advance. I haven't forgotten my promise to help with documentation -- I've just been really needing to get to this release before I can though. :(

Offlein avatar May 10 '24 00:05 Offlein