Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Enum parsing error: TypeError: Cannot read private member from an object whose class did not declare it (codesandbox repro included) #3611

Open
generalleger opened this issue Jul 2, 2024 · 2 comments · May be fixed by #3926

Comments

@generalleger
Copy link

Reproduction: https://codesandbox.io/p/sandbox/zod-test-d6y6ts

I recently upgraded to 3.23.x from 3.22.4 and starting getting this error:

TypeError: Cannot read private member from an object whose class did not declare it.

After some digging, I narrowed it down to ZodEnums parsing under specific circumstances. It happens when a ZodEnum has been deep cloned (in this case with lodash) and is then added as value of a ZodObject.

See the reproduction for details and some cases that do and don't work. It's the parsing on the last line that causes the error. Comment it out, and the error goes away.

Edit the package.json to 3.22.4 and the error also disappears.

I think this might be a related issue: #3520

Thanks!

@DeadOce4n
Copy link

I'm also experiencing this on 3.23.8, as a temporary workaround I'm using a union of string literals:

const myEnum = z.union([z.literal("someValue"), z.literal("otherValue")]);

@alon-gb
Copy link

alon-gb commented Dec 27, 2024

I've looked into this in the past few days. I believe the problem is not strictly in the Zod code that uses the internal lookup (added here: #2659), but rather in the javascript code that is generated by typescript.

It seems that the TypeScript compiler adds some initialization code in the ctor, which stores the private members (like #cache) on a static WeakMap. Later, when accessing those members, the __classPrivateFieldGet __classPrivateFieldGet, which are generated by the compiler and added to the top of the js file, throw if the WeakMap does not have an entry for the current instance.

This means that it's impossible to clone a ZodEnum instance, and I, for one, see this as an unwanted side-effect and actually a bug in Zod.

I have a few suggestions here:

  1. Making the optimization configurable (opt-out as needed). I don't expect enums with few values to benefit from the optimization that much.
  2. Implementing the lookup in a way that uses exactly the same approach that exists now, just not throw. Effectively, it'll be a lazy-loaded thing.
  3. Implementing the lookup as a closure inside _parse instead of a private instance member. I believe this is actually the best approach as it ticks all the boxes and allows cloning. The lookup will be initialized on the first call, like today, but will allow cloning.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants