inertia: DOMException: Failed to execute 'replaceState' on 'History': # could not be cloned

Versions:

  • @inertiajs/inertia version: 0.9.2
  • @inertiajs/inertia-vue3 version: 0.4.7

Describe the problem:

I am using Vue 3 Draggable package. In the event of dragging an element, I execute Inertia.put method and pass some data to Laravel. This is where this exception occurs.

Steps to reproduce:

For example, in Laravel pass a project with a list of columns to your view. Then use the Draggable component as following:

<Draggable
    v-model="project.columns"
    group="columns"
    item-key="id"
    @end="onColumnPositionChanged"
>
    <template #item="{element: column}">
        <KanbanColumn
             :column="column"
             :key="column.id"
         />
    </template>
</Draggable>

In event of onColumnPositionChanged, trigger Inertia.put method

const onCardPositionChanged = () => {
    Inertia.put('/some-route');
};

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 8
  • Comments: 57 (8 by maintainers)

Most upvoted comments

<Draggable
    v-model="project.columns"
    group="columns"
    item-key="id"
    @end="onColumnPositionChanged"
>
    <template #item="{element: column}">
        <KanbanColumn
             :column="column"
             :key="column.id"
         />
    </template>
</Draggable>

Try changing v-model="project.columns" to :list="project.columns" i was having a similar issue and this seams to have solved it for me

Source: https://github.com/SortableJS/vue.draggable.next#list

I was having the same issue

Uncaught (in promise) DOMException: The object could not be cloned. router.ts:397:4
    replaceState router.ts:398
    saveScrollPositions router.ts:73
    resetScrollPositions router.ts:91
    g router.ts:381
    (Async: promise callback)
    g router.ts:379
    (Async: promise callback)
    setPage router.ts:373
    handleInitialPageVisit router.ts:52
    init router.ts:41
    setup app.js:43
    callWithErrorHandling runtime-core.esm-bundler.js:155
    setupStatefulComponent runtime-core.esm-bundler.js:7161
    setupComponent runtime-core.esm-bundler.js:7117
    mountComponent runtime-core.esm-bundler.js:5115
    processComponent runtime-core.esm-bundler.js:5090
    patch runtime-core.esm-bundler.js:4684
    componentEffect runtime-core.esm-bundler.js:5227
    reactiveEffect reactivity.esm-bundler.js:42
    effect reactivity.esm-bundler.js:17
    setupRenderEffect runtime-core.esm-bundler.js:5173
    mountComponent runtime-core.esm-bundler.js:5132
    processComponent runtime-core.esm-bundler.js:5090
    patch runtime-core.esm-bundler.js:4684
    render2 runtime-core.esm-bundler.js:5810
    mount runtime-core.esm-bundler.js:4085
    mount runtime-dom.esm-bundler.js:1322
    <anonymous> app.js:60
    InnerModuleEvaluation self-hosted:2384
    evaluation self-hosted:2335

What I noticed is that the exception occurs when I mutate the property, having an array that comes from the backend and then passed it to the vue component as property:

 props: {
    accounts: Array,
  },

I had a computed property which used the accounts prop, and applied a filter and a map methods which then the map method mutated the original array.

The issue was gone when I cloned the accounts array using JSON.parse and JSON.stringify

JSON.parse(JSON.stringify(this.accounts))

Also read the MDN for pushState which has a size limit of 640K, but that wasn’t my case. https://developer.mozilla.org/en-US/docs/Web/API/History_API/Working_with_the_History_API#the_pushstate_method

And supported types, in my case it was a simple array of objects, but can be the issue for @oueki https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm#supported_types

I’m just going to pop this on here: https://web.dev/structured-clone/

It digs in to the new structuredClone() api and lists some of the shortcomings of the JSON.parse(JSON.stringify()) approach.

For anyone running into issues it might turn out to be a better option, or you might find you need a library like Lodash.

Hopefully this is helpful to anyone who has scrolled this far with no success!

I pulled my hair on this one for months. My solution was similar to this https://github.com/inertiajs/inertia/issues/775#issuecomment-876030983 above

Spoiler : the problem was because a “Proxy” made its way to my state.

image

So I had to find out what couldn’t be cloned ?!

image

put a breakpoint there… and started to dig into the e object until i saw this

image

I tried to “unProxy” the value with JSON.parse(JSON.stringify(formField)), and this solved the issue.

I ended up using Lodash cloneDeep to clone the data which fixed the issue: https://lodash.com/docs/#cloneDeep

Hey! Thanks so much for your interest in Inertia.js and for sharing this issue/suggestion.

In an attempt to get on top of the issues and pull requests on this project I am going through all the older issues and PRs and closing them, as there’s a decent chance that they have since been resolved or are simply not relevant any longer. My hope is that with a “clean slate” me and the other project maintainers will be able to better keep on top of issues and PRs moving forward.

Of course there’s a chance that this issue is still relevant, and if that’s the case feel free to simply submit a new issue. The only thing I ask is that you please include a super minimal reproduction of the issue as a Git repo. This makes it much easier for us to reproduce things on our end and ultimately fix it.

Really not trying to be dismissive here, I just need to find a way to get this project back into a state that I am able to maintain it. Hope that makes sense! ❤️

Same error happening here, basically we have deep object ( chart ) that comes from “$page.props.charts.orders”

Payload Demo here : https://api.npoint.io/63d8cf8b37aee1247b5a/orders Please keep in mind more data is being shared along.

When passed via Prop to the component like follows:

<chart :chart="$page.props.charts.orders" />

This will reproduce the error from OP, but if we do like @tonychuuy mentioned and have a prop as follows :

computed:{ ordersChart(){ return JSON.parse(JSON.stringify(this.$page.props.charts.orders)) } }

<chart :chart="ordersChart" />

It will work just fine, im not sure what the issue is, but seems like some deep objects are being converted to Proxy and so fails to replace the state on those.

After some time with the debugger i was able to spot the proxied object :

image

Versions

Still having this problem

Just curious, instead of Stringify then Parse, could we use structuredClone instead to solve this?

I’m getting this same error with my checkbox component.

<script setup>
import { computed } from 'vue'

const props = defineProps(['modelValue','input'])
const emit = defineEmits(['update:modelValue'])

const value = computed({
  get() {
    return props.modelValue
  },
  set(value) {
    emit('update:modelValue', value)
  }
})
</script>

<template>
  <div>
    <template v-for="option in input.options">
        <input type="checkbox" v-model="value" :name="input.id" :value="{ id: option.id, value: option.value }" />
        <label>{{ option.label }}</label>
    </template>
  </div>
</template>

This fixes it, but just seems dirty/unnecessary

-    emit('update:modelValue', value)
+    emit('update:modelValue', JSON.parse(JSON.stringify(value)))

My understanding of the issue is when you modify a value that came as “props”, event if it’s nested deep down in an object.

I ran into the same problem and found another possible workaround:

For whatever reason it appears that if I mutate the array part of the prop with something like array.splice() instead of setting that value to a new array with something like array.filter(), it doesn’t seem to trip the error.

For example, let’s say I have a prop data structure like this:

  someProp: {
    someInt: 3,
    someArray: [
      {
        name: "someObject1",
        id: 1,
      },
      {
        name: "someObject2",
        id:2,
      }
    ],
    someString:  "string",
  },

…and I want to remove “someObject1” based on it’s id.

If I use someArray.filter(), like so, I trip the mysterious “Object could not be cloned” error:

let idToRemove = 1;
this.someProp.someArray = this.someProp.someArray.filter( arrayItem => {
  return arrayItem.id !== idToRemove;
});

If, however, I use someArray.findIndex() and someArray.splice(), I don’t trip the error.

let idToRemove = 1;
let indexToRemove = this.someProp.someArray.findIndex( arrayItem => {
  return arrayItem.id == idToRemove;
});
this.someProp.someArray.splice(indexToRemove, 1);

I’m not sure what layer of the JavaScript/Inertia/Vuejs stack is causing this odd behavior, but I hope this information helps to work around and/or fix the issue.

@reinink @iamohd - I am having the same issue, did you find a fix?

@iamohd - can you show how to do the temporary solution in the mean time?

For example

import { usePage } from '@inertiajs/inertia-vue3';
import { reactive } from 'vue';

const obj = reactive({ ... usePage().props.value.someObject });

Hi @jechazelle

As a temporary solution you can clone the prop into a new reactive variable and use it

Just make sure u truly clone it, not making a shallow copy.

Hi,

Have you found a solution @iamohd @reinink ?

I have a same issue when I use vuedraggable in my project.

I have an error when I drag my item : Uncaught DOMException: Failed to execute ‘replaceState’ on ‘History’: #<Object> could not be cloned.

My code : https://stackblitz.com/edit/vue-shifting-array-elements-47h7cu

Great, I will make a repo to reproduce this issue and post the link here

This is a strange issue. From what it sounds like, there is some type of page object data structure that’s causing this error. I am using the example data above that you’re saying is causing this issue, and I am unable to reproduce this. Basically, to fix this, I need to be able to reproduce it.

I don’t really want access to your full app. Much better is a very simple Laravel/Inertia/Vue3 app that reproduces this issue with just one or two endpoints, and one or two components. If you can provide that, I’ll happily look deeper into this. 👍