studio icon indicating copy to clipboard operation
studio copied to clipboard

Prisma Studio or Data Browser: `Do not know how to serialize a BigInt`

Open yovanoc opened this issue 4 years ago • 61 comments

On the latest version

image

yovanoc avatar Jan 21 '21 17:01 yovanoc

@yovanoc I am getting this exact error as well when trying to view my data inside Prisma Studio (some of my columns are BigInt's).

This can be reproduced by just having any model with any field that is aBigInt

KhaVNguyen avatar Jan 22 '21 02:01 KhaVNguyen

I tried to fix it using the proposed solution here in my own code: image

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt

I believe it needs to be done on Prisma's end though

KhaVNguyen avatar Jan 22 '21 02:01 KhaVNguyen

I am also experiencing this issue with BigInt. I hope this can be solved soon. This seems to affect prisma as a whole as well

yoroshikun avatar Jan 26 '21 13:01 yoroshikun

Hey everyone, I'm going to take a look at this very soon, I can reproduce the problem as well.

@yoroshikun I can't seem to be able to see an issue with Prisma Client or Migrate on 2.15.0, could you elaborate what you mean by This seems to affect prisma as a whole as well? Thanks!

sdnts avatar Jan 26 '21 13:01 sdnts

Sorry for the late reply, I have done some testing and the issue is not from Prisma not knowing how to deserialize but the framework next.js not being able to. (It affected both pages and API routes).

But yes as described above I can also reproduce the issue with Prisma studio and for now, have swapped to storing the values as strings as a fallback.

yoroshikun avatar Jan 30 '21 07:01 yoroshikun

Hello everyone! So this should be fixed in Prisma version 2.16.0 (due today). Please let me know if you're still seeing issues after it goes out. Note that there still is one issue https://github.com/prisma/studio/issues/621 that I'm going to tackle soon.

@yoroshikun Prisma Client returns real JS BigInts for Prisma BigInts, which aren't serializable, maybe that's why NextJS is also struggling.

sdnts avatar Feb 02 '21 10:02 sdnts

@madebysid I am getting this error on an introspected wordpress database running on Microsoft SQL Server (azure) with Yoast (wordpress-seo) installed. The call I'm using is is in a simple express server:

app.get("/select", async (req, res) => {
  try {
    const table = req.query.table;
    const limit = parseInt(req.query.limit, 10);
    const data = await prisma[table].findMany({
      take: limit,
    });
    res.send(data);
  } catch (error) {
    res.status = 500;
    res.send({ error: true, message: error.message });
  }
});

On the route http://localhost:3001/select?table=wp_yoast_seo_links&limit=10 the response is:

{
  "error": true,
  "message": "Do not know how to serialize a BigInt"
}

How can I go about returning data with BigInts in it?

tsdexter avatar Mar 10 '21 05:03 tsdexter

@madebysid I've fixed this for now by changing the schema like so:

model wp_yoast_seo_links {
  // id             BigInt  @id @default(autoincrement())
  id             Int     @id @default(autoincrement())
  url            String  @db.NVarChar(255)
  // post_id        BigInt
  post_id        Int
  // target_post_id BigInt
  target_post_id Int
  type           String  @db.NVarChar(8)
  language       String? @db.NVarChar(32)
  region         String? @db.NVarChar(32)

  @@index([post_id, type], name: "link_direction")
}

All of the BigInt's in my schema are for id and foreign key id fields on third party tables...whereas the first party tables such as wp_posts just use regular Int so I would imagine I shouldn't have any issues with this change - can you think of any possible issues with this? Thanks

tsdexter avatar Mar 10 '21 05:03 tsdexter

Hey @tsdexter, IIUC Studio is not involved in your setup at all, right? Is this is general question? (Happy to help either way, just wondering)

The underlying issue is that when you use a BigInt in a field in your schema, not only does your DB use a BigInt (if it is supported), but Prisma Client also now returns a real Javascript BigInt for that field. Weirdly enough, the native JSON.stringify does not work with BigInts. If you try running JSON.stringify(BigInt(34)) in a Node REPL, you'll see this error. It doesn't work in browsers either.

So in your case, the issue is that you're using res.send in your request handler, and express internally tries to JSON.stringify your response: res.send in express, express' stringify function

Again, this has nothing to do with Express, it's just that these two JS language features do not work together for whatever reason.

So here are a few ways to address this:

  1. You could change the BigInt to an Int like you've already done. This is far from ideal, since you might actually WANT a BigInt.
  2. Treat BigInts as strings. In your specific case, you might be able to get away with a BigInt().toString() to convert the integer into a string. That way, Express will see your BigInt as a string, and JSON.stringify will work as expected. It'll be manual work to make sure you change all BigInts to strings, but it might be feasible, depending on what your (client-side) app wants.
  3. Take care of stringifyingBigInts yourself. This is a lot more involved (and is ultimately what I do in Studio as well). Here's the gist of it: https://dev.to/benlesh/bigint-and-json-stringify-json-parse-2m8p. This is very similar to 2., but it works better if you want real BigInts client-side. If you prefix all BigInt strings with a prefix, you can identify such strings and run BigInt("prefix::33434".slice(0, 8)) client side to get back a real BigInt. Just be careful that you use a prefix that won't also naturally appear in regular strings.

Hopefully this was helpful and gave you a few ideas! if you have more questions, it'd probably be more useful to the community if you could start a discussion, and tag me there, I'm happy to help.

can you think of any possible issues with this? Thanks

It's hard for me to tell you what would and wouldn't work, since it is highly dependent on your app :D If you don't have a specific reason to use Ints or BigInts in your ID fields, I'd generally recommend using cuid() instead, since it usually works better (you don't have to worry about "running out" etc.), and it circumvents this issue as well!

sdnts avatar Mar 10 '21 10:03 sdnts

@tsdexter 👋

The easiest workaround as of now is to add the toJSON method on the prototype so that serialisation works well.

BigInt.prototype.toJSON = function() {       
  return this.toString()
}

ryands17 avatar Mar 10 '21 10:03 ryands17

@snettah 👋

This will work fine if the number is in the limits that JavaScript supports. For very large numbers, you would need to use a string.

ryands17 avatar May 19 '21 05:05 ryands17

@tsdexter 👋

The easiest workaround as of now is to add the toJSON method on the prototype so that serialisation works well.

BigInt.prototype.toJSON = function() {       
  return this.toString()
}

Hi! I am using prisma client 3.5.0 with nextjs v12.0.4 and i am facing this same issue. Where do i implement your solution? I tried it in a *.d.ts file but it didn't have any effect

waptik avatar Nov 28 '21 13:11 waptik

@tsdexter 👋 The easiest workaround as of now is to add the toJSON method on the prototype so that serialisation works well.

BigInt.prototype.toJSON = function() {       
  return this.toString()
}

Hi! I am using prisma client 3.5.0 with nextjs v12.0.4 and i am facing this same issue. Where do i implement your solution? I tried it in a *.d.ts file but it didn't have any effect

I used this as a workaround.

const data = await prisma.data.findMany();
const updatedData = JSON.stringify(data, (_key, value) => {
    typeof value === 'bigint' ? value = value.toString() : value
})

return { props: { updatedData } }

vrishtrix avatar Dec 17 '21 17:12 vrishtrix

this is my solution

BigInt.prototype.toJSON = function () {
  const int = Number.parseInt(this.toString());
  return int ?? this.toString();
};

roscadalexandru avatar Jan 26 '22 23:01 roscadalexandru

@tsdexter 👋

The easiest workaround as of now is to add the toJSON method on the prototype so that serialisation works well.

BigInt.prototype.toJSON = function() {       
  return this.toString()
}

Where do you add this?

necmettin avatar Jan 28 '22 09:01 necmettin

@tsdexter 👋

The easiest workaround as of now is to add the toJSON method on the prototype so that serialisation works well.

BigInt.prototype.toJSON = function() {       
  return this.toString()
}

where to add this one could you send more code here?

maheshsuthar93 avatar Feb 22 '22 13:02 maheshsuthar93

@tsdexter 👋 A solução mais fácil a partir de agora é adicionar o toJSONmétodo no protótipo para que a serialização funcione bem.

BigInt . protótipo . toJSON  =  function ( )  {        
  return  this . toString ( ) 
}

onde adicionar este você poderia enviar mais código aqui?

Crie um arquivo patch.js contendo BigInt.prototype.toJSON = function() { return this.toString() }

logo após importe ele para sua fonte import './patch.js'; or require('patch.js')

AndreLucas2103 avatar Mar 05 '22 16:03 AndreLucas2103

Had the same issue. All above was not working, but this worked (added to src/main.ts):

(BigInt.prototype as any).toJSON = function () { return Number(this) };

or (if you want the BigInt as a string in your json):

(BigInt.prototype as any).toJSON = function () { return this.toString(); };

frankps avatar Apr 16 '22 13:04 frankps

Is the best approach currently to store BigInts as strings? I'm not sure where to add the suggested implementation shown here: https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields#working-with-bigint

zkSoju avatar Jun 22 '22 10:06 zkSoju

SkSoju, the same problem here zkSoju. I don't know how or where to handle the suggested implementation. Anybody from Prisma can shed some light? Thanks!

I rather use the official solution for handling BigInt; I only need a more thorough explanation from Prisma

JayP127 avatar Jun 24 '22 06:06 JayP127

SkSoju, the same problem here zkSoju. I don't know how or where to handle the suggested implementation. Anybody from Prisma can shed some light? Thanks!

I rather use the official solution for handling BigInt; I only need a more thorough explanation from Prisma

Agreed that would probably be ideal, currently using strings, but it's a bit annoying to keep track of. If anyone has any examples that would be very helpful.

zkSoju avatar Jun 24 '22 08:06 zkSoju

SkSoju, the same problem here zkSoju. I don't know how or where to handle the suggested implementation. Anybody from Prisma can shed some light? Thanks!

I rather use the official solution for handling BigInt; I only need a more thorough explanation from Prisma

I'm using the official implementation in each of the service files and it works. Ideally the earlier solution could be used so you don't have to use the custom implementation for every query.

zkSoju avatar Jun 25 '22 00:06 zkSoju

Hey @zkSoju, can you share the version of Prisma you are using in the project where you are experiencing the Do not know how to serialize a BigInt error?

luanvdw avatar Jun 28 '22 07:06 luanvdw

Hey @zkSoju, can you share the version of Prisma you are using in the project where you are experiencing the Do not know how to serialize a BigInt error?

Hi I was actually able to fix it using graphql-scalars I figure the package specifies the serializing of BigInt.

zkSoju avatar Jun 28 '22 10:06 zkSoju

Our tests are failing due to this. Not sure why, they were working until we upgraded to 4.0.0

Screenshot 2022-06-29 at 22 33 59

taylor-lindores-reeves avatar Jun 29 '22 21:06 taylor-lindores-reeves

Are you testing Prisma Studio @leafyshark? If not, please report this at https://github.com/prisma/prisma and include more information. We would be very interesting in figuring this out of course. (Are you using raw queries in that test? Please include reply in the new issue. Thanks.)

janpio avatar Jun 30 '22 00:06 janpio

Hi, we figured out that Jest upgrade meant that it can't serialize BigInt's to JSON, and when running with multiple workers it tries to send data between them. Jest crashes without the real message describing the test failure https://github.com/facebook/jest/issues/11617#issuecomment-1068732414

Solution is to set maxWorkers: 1 in jest.config.js

taylor-lindores-reeves avatar Jun 30 '22 09:06 taylor-lindores-reeves

@tsdexter 👋

The easiest workaround as of now is to add the toJSON method on the prototype so that serialisation works well.

BigInt.prototype.toJSON = function() {       
  return this.toString()
}

If you are using TypeScript and/or ESLint, you'll need to add few more lines to make TypeScript and/or ESLint happy. The comment lines may vary depending on how you have setup your ESLint.

// eslint-disable-next-line @typescript-eslint/ban-ts-comment      <-- Necessary for my ESLint setup
// @ts-ignore: Unreachable code error                              <-- BigInt does not have `toJSON` method
BigInt.prototype.toJSON = function (): string {
  return this.toString();
};

You could also go with the approach to convert it to number like so:

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unreachable code error
BigInt.prototype.toJSON = function (): number {
  return Number(this);
};

But bare in mind that the precision that BigInt carries will be lost when converted to Number. The max value for bigserial in postgres for example is 9223372036854775807. So if you are using bigserial (which prisma will convert to BigInt, take this into consideration)

> 9223372036854775807n
9223372036854775807n
> Number(9223372036854775807n)
9223372036854776000

On the question of "Where to add this statement?" Add it to the root of your project. In my case that would be the index.ts where I initialize my server which uses Prisma as ORM.

gspasov avatar Jul 17 '22 13:07 gspasov

Wherever I used JSON.serialize() in my project, I sprinkled this code next to my real class...

export class MyClass {
    // My method, doing stuff... like
    //var mySerializeString = JSON.serialize(myObject);
}

// Some bug with Prisma and BigInt... https://github.com/prisma/studio/issues/614
(BigInt.prototype as any).toJSON = function () {
    return Number(this)
};

And it seems to work. Reading a one and a half year old thread, and the solution is this - not good.

Krillegeddon avatar Jul 18 '22 00:07 Krillegeddon

I agree, having to use this workaround after this much time is not good enough.

We've been looking into this internally and have fixed a few cases that could lead to this error. We have a few more to go though, and reproduction is a challenge in some cases.

If you have more info on how to reproduce the issue in Studio (or Data Browser in Prisma Data Platform), we'd like to hear from you, to better understand where things go wrong and how you're using BigInts.

petradonka avatar Jul 18 '22 08:07 petradonka