react icon indicating copy to clipboard operation
react copied to clipboard

Bug: React 19 Uncaught TypeError: Do not know how to serialize a BigInt

Open nuintun opened this issue 1 month ago • 4 comments

React version: 19

Steps To Reproduce

  1. Set props with bigint
import { useCallback, useState } from 'react';

interface ServiceItem {
  name: string;
  regionIds: bigint[];
}

interface MachineItem {
  name: string;
  services: ServiceItem[];
}

interface MachineItemProps {
  machine: MachineItem;
}

function Machine(props: MachineItemProps) {
  return (
    <>
      <p>{props.machine.name}</p>
      {props.machine.services.map(service => (
        <p key={service.name}>{service.name}</p>
      ))}
    </>
  );
}

export default function Page() {
  const [update, setUpdate] = useState(0);
  const [machine, setMachine] = useState(() => {
    return {
      name: 'machine1',
      services: [
        {
          name: 'service1',
          regionIds: [31321968590458880n]
        }
      ]
    };
  });

  const onClick = useCallback(() => {
    setUpdate(update => ++update);

    setMachine(() => {
      return {
        name: 'machine2',
        services: [
          {
            name: 'service2',
            regionIds: [31321968590458881n]
          }
        ]
      };
    });
  }, []);

  return (
    <>
      <Machine machine={machine} />
      <button onClick={onClick}>Update {update}</button>
    </>
  );
}

Link to code example:

https://codesandbox.io/p/sandbox/pedantic-shirley-cg3nf8

The current behavior

Throw exception

Image

Image

The expected behavior

Do not throw exception

nuintun avatar Oct 29 '25 02:10 nuintun

The error occurs because React 19 is trying to serialize the bigint values when comparing props, but bigint cannot be serialized to JSON by default. Convert the bigint values to strings, which is the most React-friendly approach:

interface ServiceItem {
  name: string;
  regionIds: string[]; // Changed from bigint[]
}

interface MachineItem {
  name: string;
  services: ServiceItem[];
}

interface MachineItemProps {
  machine: MachineItem;
}

function Machine(props: MachineItemProps) {
  return (
    <>
      <p>{props.machine.name}</p>
      {props.machine.services.map(service => (
        <p key={service.name}>{service.name}</p>
      ))}
    </>
  );
}

export default function Page() {
  const [update, setUpdate] = useState(0);
  const [machine, setMachine] = useState(() => {
    return {
      name: 'machine1',
      services: [
        {
          name: 'service1',
          regionIds: ['31321968590458880'] // String instead of bigint
        }
      ]
    };
  });

  const onClick = useCallback(() => {
    setUpdate(update => ++update);

    setMachine(() => {
      return {
        name: 'machine2',
        services: [
          {
            name: 'service2',
            regionIds: ['31321968590458881'] // String instead of bigint
          }
        ]
      };
    });
  }, []);

  // ... rest of code
}

hsparks-codes avatar Oct 29 '25 17:10 hsparks-codes

@hsparks-codes

I know this issue is caused by BigInt and only occurs in the development environment. Manually converting BigInt to a string is not an elegant solution. The best approach would be to fix this issue within React itself, rather than adding unnecessary cognitive load for developers. Moreover, this issue doesn’t exist in React 18.

nuintun avatar Oct 30 '25 01:10 nuintun

Can this fix be merged? It's a significant issue for web3 apps where BigInts are frequently used.

rcavalabs avatar Dec 08 '25 14:12 rcavalabs

@rcavalabs I have temporarily hacked it now, but the best solution is for the official internal handling of this issue.

if (__DEV__) {
  Object.defineProperty(BigInt.prototype, 'toJSON', {
    writable: false,
    enumerable: true,
    configurable: false,
    value() {
      return this.toString();
    }
  });
}

nuintun avatar Dec 09 '25 07:12 nuintun