3

I'm currently trying to validate a JSON object coming from a database into my web app, and I keep getting the error message: TypeError: Cannot read properties of undefined (reading 'traits'). There are no properties named "traits" in my Zod schema or in the JSON object that I am validating, so IDK how this could be happening.

Zod Schema:

const Image = z.object({
    type: z.literal(["profile", "banner"]),
    url: z.string(),
    width: z.number(),
    height: z.number(),
})

const Tournament = z.object({
    id: z.number(),
    name: z.string(),
    slug: z.string(),
    startAt: z.number(),
    images: z.array(Image),
    city: z.nullable(z.string()),
    addrState: z.nullable(z.string()),
    countryCode: z.nullable(z.string()),
    isOnline: z.boolean,
    venueAddress: z.nullable(z.string()),
    mapsPlaceId: z.nullable(z.string())
})

const StartggResponse = z.object({
    pageInfo: z.object({
        totalPages: z.number()
    }),
    nodes: z.array(Tournament)
})

JSON Object:

{
  "nodes": [{
    "addrState": null,
    "city": null,
    "countryCode": null,
    "id": 823671,
    "images": [
      {"type": "profile", "url": "https://images.start.gg/images/tournament/823671/image-5b201a410655f865d59a9cbd7b0e5635.png", "width": 2048, "height": 2048},
      {"type": "banner", "url": "https://images.start.gg/images/tournament/823671/image-fc95fcf9a89b8eb8f3a309113335bcdf.png", "width": 1947, "height": 902}
    ],
    "isOnline": true,
    "mapsPlaceId": null,
    "name": "GACKED",
    "slug": "tournament/gacked",
    "startAt": 1757406600,
    "venueAddress": ""
  }],

  "pageInfo": {
    "totalPages": 143
  }
}
3
  • 1
    Please share the code you use to parse the data with the schema Commented Sep 9 at 5:57
  • Here's a reproduction. Feel free to fork that and edit it into your question. Commented Sep 9 at 12:20
  • The full error message I see is TypeError: can't access property "traits", def.shape[k]._zod is undefined (you could also edit this into your question). It's coming from the normalizeDef function in zod itself (the full expression is def.shape[k]._zod.traits.has("$ZodType")), so it's unsurprising that traits doesn't appear in your code. Commented Sep 9 at 12:23

2 Answers 2

3

You forgot to call z.boolean. Change the isOnline property in Tournament to this:

isOnline: z.boolean(),

(Complete example)

Sign up to request clarification or add additional context in comments.

3 Comments

It's unfortunate that Zod allows you to create a broken validator in the first place. Feels to me like z.object ought to be typed such that z.object({ a: z.boolean }) is rejected by TypeScript, or at least z.object's implementation should eagerly validate its parameter and immediately throw if you pass it something invalid. I don't personally use Zod and don't know if there's some reason why this would be infeasible, but if you agree with me you could consider filing an issue.
Damn I should've checked harder. Thanks man!
I had a similar issue with enums, where I just wrote the movmentType: movTypes (the enum name), instead of movementType: z.enum(movTypes).
-1

The issue with your code is that you are not properly using .literal over here. .literal only takes one value in your case you should write it with an enum like this: type: z.enum(["profile", "banner"]) also for the z.boolean that's also a wrong way of writing it simply writing isOnline: boolean is the correct way.

1 Comment

".literal only takes one value"—.literal can take an array of literals and in that case it returns validator for a union type. This is mentioned in the docs (look for "To allow multiple literal values") and can be seen in the type signature.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.