Open yovanoc opened 3 years ago
@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
I tried to fix it using the proposed solution here in my own code:
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
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
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!
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.
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.
@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 BigInt
s in it?
@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
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:
BigInt
to an Int
like you've already done. This is far from ideal, since you might actually WANT a BigInt
.BigInt
s 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 BigInt
s to strings, but it might be feasible, depending on what your (client-side) app wants.BigInt
s 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 BigInt
s 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!
@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()
}
@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.
@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
@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 } }
this is my solution
BigInt.prototype.toJSON = function () {
const int = Number.parseInt(this.toString());
return int ?? this.toString();
};
@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?
@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?
@tsdexter 👋 A solução mais fácil a partir de agora é adicionar o
toJSON
mé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')
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(); };
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
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
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.
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.
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?
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.
Our tests are failing due to this. Not sure why, they were working until we upgraded to 4.0.0
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.)
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
@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.
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.
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 BigInt
s.
I tried console.log(result) after a read of bigints. Serialization worked, but I noticed that all values are printed as 1n, 2n, 3n etc.
However, when trying to do console.log(JSON.stringify(result)) - I get the error.
I have no idea why JSON should serialize bigints differently than normal ints? I think it ought to be the same, but just possibly there are more digits? But, I just tried that, and the number is truncated and exponent is shown...
However, problem seems to be in JSON and not Prisma. Prisma is building the object by the book it seems.
However, I can see there is a package called json-bigint. If they have managed to do a workaround that makes JSON work by just including a package, perhaps you can make that package a dependency to Prisma? Or implement the same thing? I haven't tried it though.
The workaround is however not very good. It just makes code not break, but if there are really big numbers (that require BigInt), it will not work. So I need to come up with a better solution before my project hits production.
@Krillegeddon is right, the problem is with JSON itself and not prisma, JSON does not support BigInt.
JSON.stringify({a:10n})
will throw the same exception: 'Uncaught TypeError: Do not know how to serialize a BigInt'
btw: the 'n' suffix means it's a bigInt
I've found this article: https://dev.to/benlesh/bigint-and-json-stringify-json-parse-2m8p it helped me to make a work around
// Serialize
const json = JSON.stringify(data, (key, value) =>
typeof value === "bigint" ? `BIGINT::${value}` : value
);
// Deserialize
const backAgain = JSON.parse(json, (key, value) => {
if (typeof value === "string" && value.startsWith('BIGINT::')) {
return BigInt(value.substr(8));
}
return value;
});
UPDATE: I've looked at the prisma and for a better work around they have a customized implementation of JSON.stringify
// now my unit service returns a units = prisma.unit.findMany(...)
return JSON.stringify(units, (key, value) => (typeof value === 'bigint' ? value.toString() : value))
// and my controller returns a express reponse
const unitEntities = await unitService.getAllUnits()
response.status(200).send(unitEntities) // !IMPORTANT do not use response.json but response.send, otherwise it wont work
@Rainer2465 @Krillegeddon @gspasov you have some nice ideas on fixing this locally for you, that's great! We would really appreciate if you give us some hints on where the error happens for you(studio/data browser) as well as any other useful information that would help us reproduce this bug locally(prisma version, schema of the model where the error happens, any other steps you found that get you to this error) Thanks a lot for helping us out!
@Rainer2465 @Krillegeddon @gspasov you have some nice ideas on fixing this locally for you, that's great! We would really appreciate if you give us some hints on where the error happens for you(studio/data browser) as well as any other useful information that would help us reproduce this bug locally(prisma version, schema of the model where the error happens, any other steps you found that get you to this error) Thanks a lot for helping us out!
Anywhere on the browser when you try to serialize a BigInt on JSON, for me for example all my models that have BigInt when I try so send it to the frontend using Express it throws this error. You can reproduce this error on your browsers console with JSON.stringify({a:10n})
@Rainer2465, are you running into issues with Studio/Data Browser when using/serializing BigInts, or is this a more generic Prisma client issue for you?
Any updates on this? Why is the issue closed? It still appears to be an issue
We haven't been able to reproduce the issue and get to the bottom of it. @alexanderattar, are you consistently running into this? Is it in Studio or the Data Browser? Could you share a bit more details, such as how you're using BigInt
s and which steps you're taking that result in the error?
Hi @petradonka, I am also experiencing this issue using the Browser but in Prisma Studio there's no issue.
Thanks for reaching out @kcmv. Are you consistently running into this? Could you share a bit more details, such as how you're using BigInts and which steps you're taking that result in the error? Which Prisma Studio version are you using?
Jumping in here, just got this error by simply running the following raw query:
let sql = SELECT count(*) as counter FROM Users
const data: any[] = await prisma.$queryRaw(Prisma.raw(sql))
@mirelalazar, it sounds like you ran into this issue outside of Studio, just simply through the Prisma client. Is that right? If so, you could open a discussion or an issue on https://github.com/prisma/prisma to try to resolve the problem.
For anyone encountering this issue in next.js, I found this article helpful https://flaviocopes.com/nextjs-serialize-date-json/ (unrelated to Prisma)
Edit: However, parsing and stringifying the prisma response loses its type inference. (So the parsed response must be type casted as a prisma type - which is inflexible to type changes).
Related unresolved issue in Nextjs https://github.com/vercel/next.js/discussions/11498
Thanks for reaching out @kcmv. Are you consistently running into this? Could you share a bit more details, such as how you're using BigInts and which steps you're taking that result in the error? Which Prisma Studio version are you using?
Hi @petradonka, I experienced this issue whenever i try to display the bigint data into a json. My solution was to use JSON.stringify
Thanks for the details @kcmv! We've also made some progress on this issue and will be releasing some improvements with the next Prisma release that should fix the issue in most cases.
If you have made it this far in the thread and have found none of the suggestions above worked, you may want to try what finally worked for me. In my case, there was a cacheing issue in my app that prevented new changes from being compiled.
Simply enough all it took was to delete the /dist
folder and restart npm run start:dev
. Both solutions below then worked for me. Choose one or the other, or you may want to implement @Rainer2465 serialize/deserialize option if your case requires it.
In my NestJs app, this solution works in my main.ts file:
// main.ts
// 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();
};
And the suggested Prisma solution works in each service method:
// some.service.ts
async findAll() {
const data = await this.prisma.caseType.findMany();
return JSON.stringify(data, (key, value) =>
typeof value === 'bigint' ? value.toString() : value,
);
}
If you have made it this far in the thread and have found none of the suggestions above worked, you may want to try what finally worked for me. In my case, there was a cacheing issue in my app that prevented new changes from being compiled.
Simply enough all it took was to delete the
/dist
folder and restartnpm run start:dev
. Both solutions below then worked for me. Choose one or the other, or you may want to implement @Rainer2465 serialize/deserialize option if your case requires it.Global solution
In my NestJs app, this solution works in my main.ts file:
// main.ts // 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(); };
Service level solution
And the suggested Prisma solution works in each service method:
// some.service.ts async findAll() { const data = await this.prisma.caseType.findMany(); return JSON.stringify(data, (key, value) => typeof value === 'bigint' ? value.toString() : value, ); }
@jboothe Thank you. This works for me like a charm.
No need to fight with eslint in Typescript:
declare global {
interface BigInt {
toJSON(): string;
}
}
BigInt.prototype.toJSON = function (): string {
return this.toString();
};
If you're trying to use this with Typescript, I suggest you create a .ts or .js file with:
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unreachable code error
BigInt.prototype.toJSON = function (): number {
return this.toString();
};
You can also return Number(this), but I suggest toString as it has no character limiter. However, it will depend on your context.
After that, you must import or require this file in your main file (like index.ts/.js or main.ts, etc).
If you are trying to run tests with Jest, you must add this file in the installation configuration. These settings can be created in package.json with "jest: { .... }" or in a file called jest.config.ts (create this in the root).
Example:
export default {
testTimeout: 30000,
moduleFileExtensions: ['js', 'json', 'ts'],
**setupFiles: ['./my_config_file'],**
testRegex: '.*\\.spec\\.ts$',
transform: {
'^.+\\.(t|j)s$': 'ts-jest',
},
collectCoverageFrom: ['**/*.(t|j)s'],
coverageDirectory: '../coverage',
testEnvironment: 'node',
}
At this point you can create a test module, with many configs, and create an index file that imports all the configs, and just pass this index file in the setupFiles config from jest.
Our tests are failing due to this. Not sure why, they were working until we upgraded to 4.0.0
This should help you: https://github.com/prisma/studio/issues/614#issuecomment-1466901384
I believe v4 started returning a lot more non-Number types (BigInt, Decimal, maybe others). Honestly a huge pain, we're looking for a good workaround too. The worst part is that if you get a Decimal back, + does string concatenation instead of actual addition, so it broke a lot of our backend endpoints and made them produce wrong results. We have to cast every $queryRaw count/sum/etc result with Number() now.
On the latest version