19 digit unsigned big integer variable rounded to sixteenth digit

What seems to be the problem:

I have a model with 19 digit unsigned big integer ID. I passes it to component as follows:

@livewire('schedule-editor-modal', $rows->first())

In component:

public function mount($row)
{  
	$this->workplanRow = $row;
}

It mounted successfully, but after render() is called I’ve got an exception CorruptComponentPayloadException. I added Log::debug() to the SecureHydrationWithChecksum middleware and found out the following:

dehydrate

array (
    'class' => 'App\\Models\\EduProcess\\WorkplanRow',
    'id' => 1627802566207636954,
    'relations' => 
    array (
    ),
    'connection' => 'mysql',
  )

hydrate

array (
    'class' => 'App\\Models\\EduProcess\\WorkplanRow',
    'id' => 1627802566207637000,
    'relations' => 
    array (
    ),
    'connection' => 'mysql',
  )

So, as you can see, it rounded ID to the sixteenth digit. I believe that it is not related to Livewire itself, but I need help in solving this problem within Livewire.

Are you using the latest version of Livewire: Yes

This feels like the sort of thing that used to happen in the 32 bit days. What version of PHP are you using and on what OS? Is it possible that you are on a 32 bit system so integers are capped at 2^32?

I don’t think it’s integer size because a 32bit would cut off at 9 or 10 digits.
The thing I’m most curious about is why are there still 3 trailing zeros there? So what is rounding it but not for the reason to cut the digits off?

I’m really curious about this whole thing and can’t wait for someone to figure it out.

The MAX_SAFE_INTEGER in ES6 javascript is 9007199254740991 so maybe the round trip to the browser and back is hitting this limit. Can you cast it as string?

1 Like

Ahh, that makes a lot of sense. It also introduces a new problem because that isn’t castable.

That’s from the Illuminate\Queue\SerializesAndRestoresModelIdentifiers;, the thing to make models public properties.

I see three options here:

  1. Rewrite an implementation of SerializesAndRestoresModelIdentifiers that’s js friendly (converting id’s to strings and back)
  2. Store the model serverside (session/cache)
  3. 1627802566207636954 seems highly specific to the data, like a long barcode or something. Might be better off in the long run to change that column to what it actually is, reference the models that way, and use a traditional auto increment for the actual database id.

Btw, I still don’t understand why there are trailing zeros there that still make it go above the limit lol.

Thanks for replies. I’m using these big identifiers because our application integrated with internal ERP system, which generates those kind of IDs for all entities. So I can’t stop using it.

I had a similar issue where I had a model with an id column like:
$table->unsignedBigInteger('id')->primary();

It was not auto incrementing and was referencing an external source id thats retrieve for an API.

Some of the id values had a normal integer range, mostly around 8. But many of “newer” accounts ids had 18 digit or more. Those accounts that had 18 or more, when trying to update with Livewire components they would trigger the same CorruptComponentPayloadException exception.

@helloiamjohnsmith thanks for logging that info, that helped me diagnose the issue.

My solution was to just cast the id to a string, which seems to stop the rounding. The service provider that looks up the account ids still stores them as integers. So far no issues.

I added this to my model:

protected $casts = [
    'id' => 'string',
];

Using:

"laravel/framework": "^8.0"
"laravel/horizon": "^5.4"
"laravel/jetstream": "^1.4"
"laravel/sanctum": "^2.6"
"laravel/tinker": "^2.0"
"livewire/livewire": "^2.0"