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

Node hangs when console.log(new PrismaClient()) #18292

Closed
sc0ch opened this issue Mar 12, 2023 · 37 comments · Fixed by #23228
Closed

Node hangs when console.log(new PrismaClient()) #18292

sc0ch opened this issue Mar 12, 2023 · 37 comments · Fixed by #23228
Labels
bug/2-confirmed Bug has been reproduced and confirmed. domain/client Issue in the "Client" domain: Prisma Client, Prisma Studio etc. kind/bug A reported bug. topic: logging topic: prisma-client
Milestone

Comments

@sc0ch
Copy link

sc0ch commented Mar 12, 2023

Bug description

Linux - node process hangs (stuck on prisma:client:libraryEngine internalSetup +0ms)
Windows - javascript out of memory error.
Any schema.
Affected versions of @prisma/client > 4.7.0

How to reproduce

  1. npx prisma init
  2. npx prisma generate (npx prisma db push)
  3. Create index.mjs with:
    import { PrismaClient } from '@prisma/client'
    console.log(new PrismaClient())
    
  4. export DEBUG="*" && node index.mjs -> See error

Expected behavior

No response

Prisma information

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

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

model Session {
  id    Int    @id @default(autoincrement())
  key   String @unique
  value String

  @@map("sessions")
}

Environment & setup

  • OS: Windows 11, Ubuntu 22.04.2
  • Database: MySQL
  • Node.js version: 18.5.0, 19.7.0

Prisma Version

prisma                  : 4.11.0
@prisma/client          : 4.11.0
Current platform        : debian-openssl-3.0.x
Query Engine (Node-API) : libquery-engine 8fde8fef4033376662cad983758335009d522acb (at node_modules/@prisma/engines/libquery_engine-debian-openssl-3.0.x.so.node)
Migration Engine        : migration-engine-cli 8fde8fef4033376662cad983758335009d522acb (at node_modules/@prisma/engines/migration-engine-debian-openssl-3.0.x)
Format Wasm             : @prisma/prisma-fmt-wasm 4.11.0-57.8fde8fef4033376662cad983758335009d522acb
Default Engines Hash    : 8fde8fef4033376662cad983758335009d522acb
Studio                  : 0.483.0
@sc0ch sc0ch added the kind/bug A reported bug. label Mar 12, 2023
@janpio janpio added bug/1-unconfirmed Bug should have enough information for reproduction, but confirmation has not happened yet. domain/client Issue in the "Client" domain: Prisma Client, Prisma Studio etc. labels Mar 14, 2023
@janpio
Copy link
Contributor

janpio commented Mar 14, 2023

Why do you want to console.log(new PrismaClient())?

@AvIsBeastMC
Copy link

AvIsBeastMC commented Mar 19, 2023

Why do you want to console.log(new PrismaClient())?

fr

@entrptaher
Copy link

entrptaher commented Apr 5, 2023

I did this and then whenever I wanted to console.log(prisma) anywhere for any reason, it hung the whole process.

import { PrismaClient } from "@prisma/client";
let prisma = new PrismaClient();
console.log(prisma)

The issue is in 4.8.0 and all later versions while it's not present in 4.7.0 or older versions. I believe the issue is related to this optimizations.

In this release, we have decreased the size of our engine files by an average of 50%. The size of the Query Engine used on Debian, with OpenSSL 3.0.x, for example, went from 39MB to 14MB. We will also remove some smaller engines to decrease the total size in future versions.

@professor-l
Copy link

professor-l commented Apr 17, 2023

I've encountered this as well. I use a development repl in one of my projects, and though I can const p = new PrismaClient(), a subsequent p to check whether it's defined hangs the process.

This also means that declaring and defining in one line works:

const p = new PrismaClient() // runs successfully in a repl

But attempting to do so in two separate steps does not:

let p
p = new PrismaClient() // hangs the process in a repl

@janpio janpio changed the title NodeJS hangs when console.log(new PrismaClient()) NodeJS hangs when console.log(new PrismaClient()) Apr 18, 2023
@janpio janpio changed the title NodeJS hangs when console.log(new PrismaClient()) Node hangs when console.log(new PrismaClient()) Apr 18, 2023
@janpio
Copy link
Contributor

janpio commented Apr 18, 2023

I can actually log new PrismaClient() fine:

const { PrismaClient } = require('@prisma/client')

async function main() {
    console.log(new PrismaClient())
}

main()
  .catch(async (e) => {
    console.error(e)
    await prisma.$disconnect()
    process.exit(1)
  })

When I put the output of this into a file, it is 525 MB (551.039.534 bytes) big though - so I would not be surprised if that would crash in some environments.

The output looks recursive to me in 2 places:

{
  _middlewares: MiddlewareHandler { _middlewares: [] },
  _getDmmf: [Function (anonymous)],
  _getProtocolEncoder: [Function (anonymous)],
  '$extends': [Function: $extends],
  _extensions: MergedExtensionsList { head: undefined },
  _previewFeatures: [],
  _rejectOnNotFound: undefined,
  _clientVersion: '4.13.0',
  _activeProvider: 'postgresql',
  _dataProxy: false,
  _tracingConfig: { enabled: [Getter], middleware: [Getter] },
  _clientEngineType: 'library',
  _errorFormat: 'colorless',
  _baseDmmf: {
    datamodel: { enums: [], models: [Array], types: [] },
    datamodelEnumMap: {},
    modelMap: { User: [Object] },
    typeMap: {},
    typeAndModelMap: { User: [Object] },
    mappings: { modelOperations: [Array], otherOperations: [Object] },
    mappingsMap: { User: [Object] }
  },
  _engineConfig: {
    cwd: 'C:\\Users\\Jan\\Documents\\throwaway\\18292\\prisma',
    dirname: 'C:\\Users\\Jan\\Documents\\throwaway\\18292\\node_modules\\.prisma\\client',
    enableDebugLogs: false,
    allowTriggerPanic: undefined,
    datamodelPath: 'C:\\Users\\Jan\\Documents\\throwaway\\18292\\node_modules\\.prisma\\client\\schema.prisma',
    prismaPath: undefined,
    engineEndpoint: undefined,
    datasources: [],
    generator: {
      name: 'client',
      provider: [Object],
      output: [Object],
      config: [Object],
      binaryTargets: [],
      previewFeatures: []
    },
    showColors: false,
    logLevel: undefined,
    logQueries: undefined,
    env: {
      DATABASE_URL: 'postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public'
    },
    flags: [],
    clientVersion: '4.13.0',
    previewFeatures: [],
    activeProvider: 'postgresql',
    inlineSchema: undefined,
    inlineDatasources: undefined,
    inlineSchemaHash: undefined,
    tracingConfig: { enabled: [Getter], middleware: [Getter] },
    logEmitter: EventEmitter {
      _events: [Object: null prototype],
      _eventsCount: 1,
      _maxListeners: undefined,
      [Symbol(kCapture)]: false
    },
    engineProtocol: 'graphql'
  },
  _engine: LibraryEngine {
    datamodel: '// This is your Prisma schema file,\n' +
      '// learn more about it in the docs: https://pris.ly/d/prisma-schema\n' +
      '\n' +
      'generator client {\n' +
      '  provider = "prisma-client-js"\n' +
      '}\n' +
      '\n' +
      'datasource db {\n' +
      '  provider = "postgresql"\n' +
      '  url      = env("DATABASE_URL")\n' +
      '}\n' +
      '\n' +
      'model User {\n' +
      '  id    Int     @id @default(autoincrement())\n' +
      '  email String  @unique\n' +
      '  name  String?\n' +
      '}\n',
    config: {
      cwd: 'C:\\Users\\Jan\\Documents\\throwaway\\18292\\prisma',
      dirname: 'C:\\Users\\Jan\\Documents\\throwaway\\18292\\node_modules\\.prisma\\client',
      enableDebugLogs: false,
      allowTriggerPanic: undefined,
      datamodelPath: 'C:\\Users\\Jan\\Documents\\throwaway\\18292\\node_modules\\.prisma\\client\\schema.prisma',
      prismaPath: undefined,
      engineEndpoint: undefined,
      datasources: [],
      generator: [Object],
      showColors: false,
      logLevel: undefined,
      logQueries: undefined,
      env: [Object],
      flags: [],
      clientVersion: '4.13.0',
      previewFeatures: [],
      activeProvider: 'postgresql',
      inlineSchema: undefined,
      inlineDatasources: undefined,
      inlineSchemaHash: undefined,
      tracingConfig: [Object],
      logEmitter: [EventEmitter],
      engineProtocol: 'graphql'
    },
    libraryStarted: false,
    logQueries: false,
    logLevel: 'error',
    libraryLoader: DefaultLibraryLoader {
      libQueryEnginePath: null,
      platform: null,
      config: [Object]
    },
    logEmitter: EventEmitter {
      _events: [Object: null prototype],
      _eventsCount: 1,
      _maxListeners: undefined,
      [Symbol(kCapture)]: false
    },
    engineProtocol: 'graphql',
    datasourceOverrides: [Object: null prototype] {},
    libraryInstantiationPromise: Promise { <pending> }
  },
  _fetcher: RequestHandler {
    logEmitter: EventEmitter {
      _events: [Object: null prototype],
      _eventsCount: 1,
      _maxListeners: undefined,
      [Symbol(kCapture)]: false
    },
    client: {
       ... RECURSION 1 HERE ...
    },
    dataloader: DataLoader { options: [Object], tickActive: false, batches: {} }
  },
  _metrics: MetricsClient {
    _engine: LibraryEngine {
      datamodel: '// This is your Prisma schema file,\n' +
        '// learn more about it in the docs: https://pris.ly/d/prisma-schema\n' +
        '\n' +
        'generator client {\n' +
        '  provider = "prisma-client-js"\n' +
        '}\n' +
        '\n' +
        'datasource db {\n' +
        '  provider = "postgresql"\n' +
        '  url      = env("DATABASE_URL")\n' +
        '}\n' +
        '\n' +
        'model User {\n' +
        '  id    Int     @id @default(autoincrement())\n' +
        '  email String  @unique\n' +
        '  name  String?\n' +
        '}\n',
      config: [Object],
      libraryStarted: false,
      logQueries: false,
      logLevel: 'error',
      libraryLoader: [DefaultLibraryLoader],
      logEmitter: [EventEmitter],
      engineProtocol: 'graphql',
      datasourceOverrides: [Object: null prototype] {},
      libraryInstantiationPromise: [Promise]
    }
  },
  user: {
    findUnique: [Function (anonymous)],
    findUniqueOrThrow: [Function (anonymous)],
    findFirst: [Function (anonymous)],
    findFirstOrThrow: [Function (anonymous)],
    findMany: [Function (anonymous)],
    create: [Function (anonymous)],
    createMany: [Function (anonymous)],
    delete: [Function (anonymous)],
    update: [Function (anonymous)],
    deleteMany: [Function (anonymous)],
    updateMany: [Function (anonymous)],
    upsert: [Function (anonymous)],
    aggregate: [Function (anonymous)],
    groupBy: [Function (anonymous)],
    count: [Function (anonymous)],
    name: 'User'
  },
  [Symbol()]: {
      ... RECURSION 2 HERE ...
   }
}

Both cases are roughly 100.000 lines long in my file.

Not optimal.

@jonschlinkert
Copy link

I experience this too. I've had to create work arounds everywhere in our application that might have client (an instance of prisma) on a class instance. Otherwise the server freezes anytime something logs out.

To fix this, anywhere recursive information is added to the object I recommend using Reflect.defineProperty so that it can be made non-enumerable, instead of simple accessor assignment.

Example:

Reflect.defineProperty(prisma, Symbol(), {
  value: {...},
  enumerable: false
});

@janpio
Copy link
Contributor

janpio commented May 17, 2023

This seems to also happen when logging the tx inside an interactive $transaction - which makes sense as that is just another Client instance: #19137

@SD-Gaming
Copy link

I have met this issue too,

OS:  win10 x64

node: 18.15.4 x64

prisma: 4.16.1 client 4.16.1

@Xaliks
Copy link

Xaliks commented Aug 13, 2023

+1

node 20.5.1
prisma 5.1.1

const { PrismaClient } = require("@prisma/client");
const client = new PrismaClient();

console.log(client);

@Druue Druue 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 22, 2023
@Druue
Copy link
Contributor

Druue commented Aug 22, 2023

Can confirm this same behaviour on mac too

Image

@janpio
Copy link
Contributor

janpio commented Aug 22, 2023

Duplicate: #19648

@Xaliks
Copy link

Xaliks commented Aug 22, 2023

I also can't inspect client
screenshot

@aqrln
Copy link
Member

aqrln commented Aug 22, 2023

Also reproduced in #19648 (comment), for me it was 152 MiB of output on Prisma 4.15.0 and the process hanging indefinitely on Prisma 5.2.0-dev.

Analysis: #19648 (comment)
Note: #19648 (comment)

@janpio
Copy link
Contributor

janpio commented Aug 22, 2023

Can you also confirm that it used to work fine in Prisma 4.7.0 and older @Druue?
Then we have something to start looking into what changed.

@Druue
Copy link
Contributor

Druue commented Aug 23, 2023

This is the behaviour that I see on 4.7.0; warning if you're sensitive to flashing imagery.
Not sure that this is necessarily working as intended, but it doesn't hang at least

Screen.Recording.2023-08-23.at.16.42.22.mov

@janpio
Copy link
Contributor

janpio commented Aug 23, 2023

It's art 🤣

@at-vpd
Copy link

at-vpd commented Oct 2, 2023

this stumped me for 2 days - why does it happen?

@llimllib
Copy link

llimllib commented Oct 5, 2023

This issue prevents me from using prisma in the node REPL; I don't literally want to log the output of the client, but I do want to use it in a repl.

Here's a node REPL script that reproduces the issue:

const repl = require("node:repl");

const r = repl.start("> ");
r.context.prisma = new (require("@prisma/client").PrismaClient)();

run that script, type pri, node tries to autocomplete prisma and the process immediately hangs; it's not even responsive to ctrl+c interrupt at that point.

@wodCZ
Copy link

wodCZ commented Oct 5, 2023

@llimllib you can work around the issue with this:

const repl = require("node:repl");

const r = repl.start("> ");
r.context.prisma = new (require("@prisma/client").PrismaClient)();
r.context.prisma[Symbol.for('nodejs.util.inspect.custom')] = 'PrismaClient';

as suggested here: #19648 (comment)

jtoar pushed a commit to redwoodjs/redwood that referenced this issue Dec 5, 2023
…sole to hang (#9623)

The related Prisma issue: prisma/prisma#18292

It basically causes all kinds of Node REPLs that use PrismaClient to
hang when users type the variable name that holds the client. Adding a
workaround as suggested in the Prisma thread.

Fixes #8817
jtoar pushed a commit to redwoodjs/redwood that referenced this issue Dec 5, 2023
…sole to hang (#9623)

The related Prisma issue: prisma/prisma#18292

It basically causes all kinds of Node REPLs that use PrismaClient to
hang when users type the variable name that holds the client. Adding a
workaround as suggested in the Prisma thread.

Fixes #8817
Jolg42 added a commit that referenced this issue Dec 6, 2023
Related to #18292

This was in my stash from a recent train ride 🚋

When trying it in the `./sandbox` directory, `console.log(prisma)` works.
@codeinearts
Copy link

codeinearts commented Feb 2, 2024

I'm running into an issue that may be a different manifestation of this same issue. In Visual Studio Code, whenever I attempt to debug into a class that extends PrismaClient, the node process hangs. Also if I attempt to inspect the instance of this class before stepping into it, the node process hangs. I'm not able to debug any of my classes that extend PrismaClient because of this. I wonder if the debugging issue has something to do with the debugger inspecting the PrismaClient instance for a watch locals or something and this inspecting leads to the same error as logging the PrismaClient instance.

I'm also experiencing this issue after upgrading from 4.11.0 to latest 5.9.1.

When attaching the debugger to some breakpoints while working on some client extensions, it hangs the whole application (drove me crazy today, just in the middle of a deadline 🫠)

@codeinearts
Copy link

@llimllib you can work around the issue with this:

const repl = require("node:repl");

const r = repl.start("> ");
r.context.prisma = new (require("@prisma/client").PrismaClient)();
r.context.prisma[Symbol.for('nodejs.util.inspect.custom')] = 'PrismaClient';

as suggested here: #19648 (comment)

I can confirm this workaround also fixes my issue using the debugger when extending PrismaClient as a class in the context of a NestJS application

@Injectable()
export class PrismaService
  extends PrismaClient<PrismaClientOptions, "query" | "error">
  implements OnModuleInit, OnModuleDestroy
{
  private readonly logger = new Logger(PrismaService.name);

  constructor(private readonly configService: ApiConfigService) {
    super({
      log: [
        {
          emit: "event",
          level: "query",
        },
        {
          emit: "event",
          level: "error",
        },
        {
          emit: "stdout",
          level: "info",
        },
        {
          emit: "stdout",
          level: "warn",
        },
      ],
    });

    /**
     * new PrismaClient versions hangs debugger
     * https://github.com/prisma/prisma/issues/18292#issuecomment-1749123704
     */
    Object.assign(this, {
      [Symbol.for("nodejs.util.inspect.custom")]: "PrismaCLient",
    });

    this.$on("error", (event) => {
      this.logger.log(event.target);
    });

    this.$on<any>("query", (event: Prisma.QueryEvent) => {
      const { query, timestamp, duration } = event;
      const collection = query.split("(")[0];
      this.logger.log(
        { collection, timestamp, duration, query },
        "PRISMA QUERY DEBUG"
      );
    });

    this.$use(async (params, next) => {
      const before = Date.now();

      const result = await next(params);

      const after = Date.now();

      const duration = after - before;

      this.logger.log(
        { collection: params.model, operation: params.action, duration },
        `Query ${params.model}.${params.action} took ${duration} ms`
      );

      return result;
    });
  }

  async onModuleInit() {
    await this.$connect();
  }

  async onModuleDestroy() {
    await this.$disconnect();
  }
}

@janpio
Copy link
Contributor

janpio commented Mar 4, 2024

Hey everyone that commented in this issue before, could you please try to temporarily install prisma@dev and @prisma/client@dev in your project and see if this fixes the problem? #23228 should have fixed this and will be included in the next release, but of course a confirmation of it now working as intended would be nice.

@wodCZ
Copy link

wodCZ commented Mar 5, 2024

@janpio I've just tested and can confirm that the dev version no-longer freezes REPL instance when the command would output anything with prisma instance on it.

With 5.10.2 it does freeze, so the fix must've addressed it correcly.

Can't wait for the release, thanks SevInf and team for the fix 🙌

@YoannBuzenet
Copy link

It works with the dev version. Thank you !

@thw0rted
Copy link

Hi @janpio , since it looks like the actual fix in the PR is only a few lines (and the rest are tests...), would it be possible to get a backport for those of us still stuck on 4.x? The [Symbol.for...] fix a few comments up is helpful, but has to be re-applied every time I launch the REPL.

@janpio
Copy link
Contributor

janpio commented Apr 19, 2024

Unfortunately not, we never maintain older versions by backporting changes or fixes.

You would need to do that yourself in a fork and publish it under your own package name.
Probably you can achieve something similar using https://www.npmjs.com/package/patch-package

@divmgl
Copy link

divmgl commented May 13, 2024

Thanks for this fix.

I want to add another case where this was problematic. We have a dependency injection container where we store our Prisma client for use in parts of the app that require it. Dependencies are lazily loaded, but we connect the Prisma client on app launch, so it's always loaded.

There have been moments where we need to inspect other parts of the container, so we'll console.log the container. This is probably a bad idea, but we would log out the full container to inspect it. This would unfortunately hang the entire process during development and we were never able to figure out why this was happening. So now we know!

So thank you for fixing this bug! Super helpful!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug/2-confirmed Bug has been reproduced and confirmed. domain/client Issue in the "Client" domain: Prisma Client, Prisma Studio etc. kind/bug A reported bug. topic: logging topic: prisma-client
Projects
None yet
Development

Successfully merging a pull request may close this issue.