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

Prisma Client errors with "TypeError: Cannot create proxy with a non-object as target or handler" when using result client extension with no needs and count method #20499

Closed
semoal opened this issue Aug 2, 2023 · 8 comments · Fixed by #20504
Labels
5.1.0 bug/2-confirmed Bug has been reproduced and confirmed. kind/bug A reported bug. team/client Issue for team Client. tech/typescript Issue for tech TypeScript. topic: clientExtensions
Milestone

Comments

@semoal
Copy link

semoal commented Aug 2, 2023

Bug description

Just upgraded to 5.1.0, and after adjusting the Array shortcut breaking change, I have run the testing suite and this test fails, I'm not quite sure how to debug this.

Any help or question is appreciated and I would love to help.

 FAIL  src/controllers/v1/users.controller.test.ts > Users > Search > should search
TypeError: Cannot create proxy with a non-object as target or handler
 ❯ xe ../../packages/prisma-client/client/runtime/library.js:26:5353
 ❯ Ds ../../packages/prisma-client/client/runtime/library.js:112:2696
 ❯ visitor ../../packages/prisma-client/client/runtime/library.js:112:3823
 ❯ $r ../../packages/prisma-client/client/runtime/library.js:112:3062
 ❯ Is ../../packages/prisma-client/client/runtime/library.js:112:3751
 ❯ l ../../packages/prisma-client/client/runtime/library.js:126:10330
 ❯ search src/controllers/v1/users.controller.ts:149:17
    147|     : { name: Prisma.SortOrder.asc };
    148|
    149|   const count = await prisma.user.count();

Our User schema is quite big so it's complicated to share.

I'm using Postgres, Node 18.13.0, Typescript 5.0.4 and a PNPM monorepo if it helps.

How to reproduce

Expected behavior

No response

Prisma information

// Add your schema.prisma
// Add your code using Prisma Client

Environment & setup

  • OS: Macosx
  • Database: Postgresql
  • Node.js version: 18.13.0

Prisma Version

5.1.0
@semoal semoal added the kind/bug A reported bug. label Aug 2, 2023
@janpio
Copy link
Member

janpio commented Aug 2, 2023

Can you please share the actual code that is being executed there?
Did I understand correctly that you upgraded from 4.x to 5.1 directly and now get this error?

@janpio janpio added bug/0-unknown Bug is new, does not have information for reproduction or reproduction could not be confirmed. team/client Issue for team Client. topic: count() https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#count labels Aug 2, 2023
@semoal
Copy link
Author

semoal commented Aug 2, 2023

Yes, exactly;

The code is something as simply as calling that model with count:

export async function search(
  params: SearchParams
): TypedPaginatedResponse<(User & { onboarding: { id: string } | null })[]> {
  const count = await prisma.user.count();

  return {
    data: [],
    pagination: {
      count: [].length,
      totalCount: count,
    },
  };
}

And the test with Vitest:

    it<TestContext>("should search", async () => {
      const r = await search(defaultPagination);
      expect(r.data.length).toBeGreaterThan(0);
    });

@Jolg42 Jolg42 added tech/typescript Issue for tech TypeScript. topic: vitest labels Aug 2, 2023
@semoal
Copy link
Author

semoal commented Aug 2, 2023

The previous version I was of Prisma its: 4.15.0, and Vitest I'm using 0.34.1 (latest) but tried with 0.32.0 and got the same error;

Btw; it's only happening on this model, because I run different tests on other models.count() and works fine.

This is the User model, if it helps:

model User {
  id                 String       @id @default(uuid()) @db.Uuid
  email              String?
  name               String?
  surname            String?
  avatar             String?
  externalId         String?
  ssn                String?
  loginMethod        LoginMethod?
  accessControlList  String[]
  createdAt          DateTime     @default(now()) @db.Timestamptz(3)
  updatedAt          DateTime     @updatedAt @db.Timestamptz(3)
  deactivatedAt      DateTime?    @db.Timestamptz(3)
  registeredAt       DateTime?    @db.Timestamptz(3)
  status             UserStatus?
  /// Optional to allow returning null when we send users to the front-end
  passwordSalt       String?
  /// Optional to allow returning null when we send users to the front-end
  password           String?
  entityId           String?      @db.Uuid
  passwordExpired    Boolean?
  userType           UserType     @default(ADVISOR_FF)
  defaultRole        UserRole     @default(ADVISOR)
  isBlind            Boolean?
  isElderly          Boolean?
  hasChildTaxCredit  Boolean?
  hasDependentCredit Boolean?

  middleName             String?
  birthDate              DateTime?       @db.Timestamptz(3)
  retirementDate         DateTime?       @db.Timestamptz(3)
  retirementAge          Int?
  numberOfDependents     Int?
  riskLevel              Int?
  investmentObjective    Int?
  countryOfCitizenshipId String?
  countryOfResidenceId   String?
  prefix                 Prefix?
  sufix                  Sufix?
  gender                 Gender?
  maritalStatus          MaritalStatus?
  marketFeel             MarketFeelings?
  riskId                 String?         @db.Uuid
  currentRisk            Risk?           @relation("userRisk", fields: [riskId], references: [id])
  dependent              Boolean?

  authenticationMethod AuthenticationMethods?
  authenticationSecret String?
  addresses            UserAddresses[]
  documents            UserDocuments[]
  phones               UserPhones[]
  portfolios           Portfolio[]
  advisorOnboardings   Onboarding[]           @relation("advisorOnboardings")
  countryOfResidence   Country?               @relation("countryOfResidence", fields: [countryOfResidenceId], references: [id])
  entity               Entity?                @relation(fields: [entityId], references: [id], onDelete: Cascade)
  countryOfCitizenship Country?               @relation("countryOfCitizenship", fields: [countryOfCitizenshipId], references: [id])
  holders              Holder[]
  benchmarks           Benchmark[]
  modelPortfolios      ModelPortfolio[]
  strategies           Strategy[]
  onboarding           Onboarding?
  activities           UserActivity[]
  taskUsers            UsersOnTasks[]
  guestGroupMembers    GroupMembers[]
  plaidExtraData       PlaidExtraData[]
  amount               Float?
  risks                Risk[]
  simpleIntegrations   Json?

  integrationStatus                IntegrationStatus?
  errorCode                        String?
  errorMessage                     String?
  riskProfile                      RiskProfile[]
  metadata                         Metadata[]
  quickViews                       QuickView[]
  factFinderTemplates              FactFinderTemplate[]
  userFactFinderCampaigns          FactFinderCampaign[]
  advisorFactFinderCampaigns       FactFinderCampaign[]              @relation(name: "advisorCampaigns")
  rebalancings                     Rebalancing[]
  taskHistories                    TaskHistory[]                     @relation("taskHistoryUser")
  affectingTaskHistories           TaskHistory[]                     @relation("userAffected")
  taskAttachments                  TaskAttachment[]
  taskComments                     TaskComment[]
  tasks                            Task[]
  mailingTemplates                 MailingTemplates[]
  collaboratingFactFinderCampaigns FactFinderCampaignCollaborators[]
  userDevices                      UserDevices[]
  assets                           Asset[]
  liabilities                      Liability[]
  expenses                         Expense[]
  factFinderCampaignFeedback       FactFinderCampaignFeedback[]
  integrations                     UserIntegration[]
  incomes                          Income[]
  insurances                       Insurance[]
  estates                          Estate[]
  liabilityAmortizations           LiabilityAmortization[]
  userGoals                        Goal[]                            @relation("retirementUser")
  headGoals                        Goal[]                            @relation("retirementAgeHead")
  spouseGoals                      Goal[]                            @relation("retirementAgeSpouse")
  taxDetails                       TaxDetail[]

  @@index([amount])
  @@index([name])
  @@index([email])
  @@index([userType])
}

It's big but worked previously fine, so dunno

@Jolg42 Jolg42 added bug/1-unconfirmed Bug should have enough information for reproduction, but confirmation has not happened yet. and removed bug/0-unknown Bug is new, does not have information for reproduction or reproduction could not be confirmed. labels Aug 2, 2023
@janpio
Copy link
Member

janpio commented Aug 2, 2023

The error message also mentions : { name: Prisma.SortOrder.asc };, while the code you shared does not. Might that be relevant?

Can you maybe isolate the schema and code into its own, standalone project so you can see if you can reproduce it? Sharing that project with us would be perfect for us to reproduce, understand and hopefully fix.

@semoal
Copy link
Author

semoal commented Aug 2, 2023

The error message also mentions : { name: Prisma.SortOrder.asc };, while the code you shared does not. Might that be relevant?

Can you maybe isolate the schema and code into its own, standalone project so you can see if you can reproduce it? Sharing that project with us would be perfect for us to reproduce, understand and hopefully fix.

I'll try to isolate but it's a large repo so it's a bit complex, but will try for sure.
About the Prisma.SortOrder.asc, was not relevant tried with the code I've pasted here and got the same error.

@semoal
Copy link
Author

semoal commented Aug 2, 2023

Got it guys!
I've had this, basically we hide the password and salt for every request we do through the default prisma singleton:

const _prisma = getPrismaClient();
const prisma = _prisma.$extends({
  result: {
    user: {
      password: {
        needs: {},
        compute() {
          return "";
        },
      },
      passwordSalt: {
        needs: {},
        compute() {
          return "";
        },
      },

On 4.5.1 worked without the needs of specifying the field, after specifying the needs: { field: true }, worked like a charm!

const prisma = _prisma.$extends({
  result: {
    user: {
      password: {
        needs: { password: true },
        compute() {
          return "";
        },
      },
      passwordSalt: {
        needs: { passwordSalt: true },
        compute() {
          return "";
        },
      },

Hope this issue it's hopeful for someone that forgot to add that, and the error is not self-descriptive at all -- I know it's complex but hehe

@semoal semoal closed this as completed Aug 2, 2023
@Jolg42 Jolg42 added topic: clientExtensions and removed topic: vitest topic: count() https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#count labels Aug 2, 2023
@SevInf SevInf reopened this Aug 2, 2023
@SevInf
Copy link
Contributor

SevInf commented Aug 2, 2023

Reopening, since it is an actual bug in 5.1. Even though there is a workaround for it (thank you for providing it, @semoal ), we need to fix it.

@SevInf SevInf added bug/2-confirmed Bug has been reproduced and confirmed. and removed bug/1-unconfirmed Bug should have enough information for reproduction, but confirmation has not happened yet. labels Aug 2, 2023
@Jolg42 Jolg42 added the 5.1.0 label Aug 2, 2023
@Jolg42 Jolg42 added this to the 5.2.0 milestone Aug 2, 2023
@Jolg42 Jolg42 changed the title Cannot create proxy with a non-object as target or handler when running prisma.count() Prisma Client errors with "TypeError: Cannot create proxy with a non-object as target or handler" when using a Client Extension Aug 2, 2023
SevInf added a commit that referenced this issue Aug 2, 2023
Problem: after #20438, we were trying to apply result extensions to
"sugared" result of `.count` method - plain number. Theoretically,
extensions should not apply there at all, but field with no `needs`
applies to every result of a corresponding model. And since result
extensions use proxies and proxy can not be created over non-objects,
the code thrown very undescriptive error instead.

Fix #20499
@SevInf SevInf changed the title Prisma Client errors with "TypeError: Cannot create proxy with a non-object as target or handler" when using a Client Extension Prisma Client errors with "TypeError: Cannot create proxy with a non-object as target or handler" when using result client extension with no needs and count method Aug 2, 2023
SevInf added a commit that referenced this issue Aug 2, 2023
* fix(client): Make sure result extensions don't break `.count`

Problem: after #20438, we were trying to apply result extensions to
"sugared" result of `.count` method - plain number. Theoretically,
extensions should not apply there at all, but field with no `needs`
applies to every result of a corresponding model. And since result
extensions use proxies and proxy can not be created over non-objects,
the code thrown very undescriptive error instead.

Fix #20499

* Update packages/client/src/runtime/core/extensions/applyAllResultExtensions.ts

Co-authored-by: Joël Galeran <Jolg42@users.noreply.github.com>

---------

Co-authored-by: Joël Galeran <Jolg42@users.noreply.github.com>
SevInf added a commit that referenced this issue Aug 2, 2023
* fix(client): Make sure result extensions don't break `.count`

Problem: after #20438, we were trying to apply result extensions to
"sugared" result of `.count` method - plain number. Theoretically,
extensions should not apply there at all, but field with no `needs`
applies to every result of a corresponding model. And since result
extensions use proxies and proxy can not be created over non-objects,
the code thrown very undescriptive error instead.

Fix #20499

* Update packages/client/src/runtime/core/extensions/applyAllResultExtensions.ts

Co-authored-by: Joël Galeran <Jolg42@users.noreply.github.com>

---------

Co-authored-by: Joël Galeran <Jolg42@users.noreply.github.com>
@SevInf
Copy link
Contributor

SevInf commented Aug 3, 2023

Fix released in 5.1.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
5.1.0 bug/2-confirmed Bug has been reproduced and confirmed. kind/bug A reported bug. team/client Issue for team Client. tech/typescript Issue for tech TypeScript. topic: clientExtensions
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants