Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

TRPC generated create mutation fails in basic polymorphic use case with zod error invalid_union #1993

Open
diesal11 opened this issue Feb 20, 2025 · 1 comment

Comments

@diesal11
Copy link

Description and expected behavior

I'm using Zenstack with the TRPC generator & react-query plugin in a NextJS app.

Given the following zmodel:

plugin trpc {
    provider = '@zenstackhq/trpc'
    output = 'src/server/api/routers/generated'
    version = 'v11'
    importCreateRouter = "@/server/api/trpc"
    importProcedure = "@/server/api/trpc"
    zodSchemasImport = "@/lib/zenstack/zod"
    generateClientHelpers = 'react'
}

generator client {
    provider = "prisma-client-js"
}

datasource db {
    provider = "postgresql"
    url      = env("DATABASE_URL")
}

enum UserType {
    UserLocal
    UserGoogle
}

model User {
    id          String       @id @default(cuid())
    type        UserType

    @@delegate(type)

    userFolders UserFolder[]
}

model UserLocal extends User {
    email    String
    password String
}

model UserGoogle extends User {
    googleId String
}

model UserFolder {
    id     String @id @default(cuid())
    userId String
    path   String

    user   User   @relation(fields: [userId], references: [id])
}

When calling the autogenerated UserFolder.create TRPC mutation as such:

    const createUserFolderMutation = api.userFolder.create.useMutation();
    ....
    await createUserFolderMutation.mutateAsync({
      data: {
        path: "/",
        userId: localUser.id,
      },
    });

The request then fails with a Zod validation error:

❌ tRPC failed on userFolder.create: [
  {
    "code": "invalid_union",
    "unionErrors": [
      {
        "issues": [
          {
            "code": "invalid_type",
            "expected": "object",
            "received": "undefined",
            "path": [
              "data",
              "user"
            ],
            "message": "Required"
          },
          {
            "code": "invalid_type",
            "expected": "object",
            "received": "undefined",
            "path": [
              "data",
              "delegate_aux_UserFolder_user_UserLocal"
            ],
            "message": "Required"
          },
          {
            "code": "invalid_type",
            "expected": "object",
            "received": "undefined",
            "path": [
              "data",
              "delegate_aux_UserFolder_user_UserGoogl_0"
            ],
            "message": "Required"
          },
          {
            "code": "unrecognized_keys",
            "keys": [
              "userId"
            ],
            "path": [
              "data"
            ],
            "message": "Unrecognized key(s) in object: 'userId'"
          }
        ],
        "name": "ZodError"
      },
      {
        "issues": [
          {
            "code": "invalid_type",
            "expected": "string",
            "received": "undefined",
            "path": [
              "data",
              "delegate_aux_UserFolder_userId_UserLoc_0"
            ],
            "message": "Required"
          },
          {
            "code": "invalid_type",
            "expected": "string",
            "received": "undefined",
            "path": [
              "data",
              "delegate_aux_UserFolder_userId_UserGoo_0"
            ],
            "message": "Required"
          }
        ],
        "name": "ZodError"
      }
    ],
    "path": [
      "data"
    ],
    "message": "Invalid input"
  }
]

Environment (please complete the following information):

  • ZenStack version: 2.11.6
  • Prisma version: 6.3.1
  • Database type: Postgresql

Additional context

I can work around this issue by creating my own TRPC mutation, which uses the simpler UserFolderCreateSchema as the input schema.

export default function createFixedRouter() {
  return createTRPCRouter({
    userFolderFixed: createTRPCRouter({
      create: procedure
        .input(z.object({ data: UserFolderCreateSchema }))
        .mutation(({ ctx, input }) => getDb(ctx).userFolder.create(input)),
    }),
  });
}

I have created an example repo with the issue here:
https://github.com/diesal11/zenstack-trpc-zod-bug

@ymc9
Copy link
Member

ymc9 commented Feb 22, 2025

Thanks for the repro. Very helpful! It seems the zod schemas it not completely cleaned up for auxiliary declarations introduced by delegate models. I'll do some further debugging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants