# “TypeError: Cannot assign to read only property 'x' of object”

> TypeError: Cannot assign to read only property 'x' of object. Frozen Redux or Immer state, React props, or Object.freeze. Copy the value, then change the copy.

Canonical: https://app369.com/fix/cannot-assign-to-read-only-property/
Last updated: 2026-11-08

The code stops with TypeError: Cannot assign to read only property '0' of object '[object Array]', or the same with a property name and #<Object>. Safari says Attempted to assign to readonly property. The code tried to change an object that is frozen or has a non-writable property. In React apps it is most often state from Redux Toolkit or Immer, or a prop, being changed in place.

**Short answer**

Do not change the object in place. Make a copy and change the copy: [...items].sort() instead of items.sort(), { ...user, name } instead of user.name = name. In Redux Toolkit, change state only inside a reducer, where Immer allows it. In React, never assign to props; lift the value into state in the parent and pass a setter down.

## **Why the object is read-only, and the fix**

1. 01 ### **Sorting or changing Redux or Immer state outside a reducer**
  > “Immer automatically freezes any state trees that are modified using produce.” [**Immer, Auto freezing**](https://immerjs.github.io/immer/freezing) Redux Toolkit runs reducers through Immer, which freezes the state it returns. state.items.sort() in a component or a selector then throws, because sort() reorders the array in place. Sort a copy.```
const items = useSelector((s) => s.todos.items);

// wrong: sorts the frozen array in place
items.sort(byDate);

// right
const sorted = [...items].sort(byDate);
```
2. 02 ### **Changing a nested object you got from the store**
  > “This protects against accidental modifications of the state tree outside of a producer.” [**Immer, Auto freezing**](https://immerjs.github.io/immer/freezing) Assigning to state.user.name outside a reducer throws for the same reason. Dispatch an action and make the change in the reducer, where writing to the draft is allowed.```
const userSlice = createSlice({
  name: 'user',
  initialState: { name: '' },
  reducers: {
    renamed(state, action) {
      state.name = action.payload;
    },
  },
});
```
3. 03 ### **Assigning to React props**
  > “Props are read-only snapshots in time: every render receives a new version of props.” [**React, Passing Props to a Component**](https://react.dev/learn/passing-props-to-a-component) In development, React freezes the props object, so props.title = 'x' throws. In production it does not throw, but the change is not tracked: nothing re-renders because of it, and it is overwritten when the parent next passes new props. Keep the value in state in the parent and pass down a function to change it.
4. 04 ### **An object frozen on purpose**
  > “This error happens only in strict mode code. In non-strict code, the assignment is silently ignored.” [**MDN, TypeError: "x" is read-only**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Read-only) Object.freeze(), a non-writable property from Object.defineProperty(), or a built-in such as Math.PI. Replace the whole object instead of changing one field. In non-strict scripts the same assignment does nothing without an error, which is why it can appear only after moving code into a module.```
let config = Object.freeze({ theme: 'light' });
config = { ...config, theme: 'dark' };
```

Checked against the vendor’s docs on November 8, 2026: [MDN: TypeError: "x" is read-only](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Read-only); [Immer docs: Auto freezing](https://immerjs.github.io/immer/freezing); [React docs: Passing Props to a Component](https://react.dev/learn/passing-props-to-a-component).

## **Rather hand it over?**

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

- [from $450**App Fix Ticket**One reproducible bug in an existing mobile or web app, diagnosed and fixed.**See scope and start**](https://app369.com/fixed-price/flutter-firebase-bug-fix/)
- [from $450**AI-Built App Rescue**A Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.****No issues worth fixing, no charge.**** If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.**See scope and start**](https://app369.com/fixed-price/ai-app-rescue/)

Related: [**React “Too many re-renders”**](https://app369.com/fix/react-too-many-re-renders/) · [**React “Maximum update depth exceeded”**](https://app369.com/fix/react-maximum-update-depth-exceeded/) · [**“Cannot read properties of undefined”**](https://app369.com/fix/cannot-read-properties-of-undefined/)

Questions

## **More on this error**

<details>

<summary>**Why does sort() throw but map() and filter() work? **+</summary>

sort(), reverse(), splice() and push() change the array in place, which a frozen array forbids (push() reports object is not extensible instead). map(), filter() and slice() return a new array and leave the original alone, as does toSorted() in Node.js 20+ and current browsers (not Hermes in React Native).

</details>

<details>

<summary>**Should I turn off Immer’s auto freeze? **+</summary>

No. Freezing is what catches this bug. With it off, the same line changes store state in place without a dispatch, so Redux never sees a new value: components do not re-render and show stale data. Copy the value instead.

</details>

<details>

<summary>**Can you fix it for me? **+</summary>

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.

</details>

A different error?

## **Describe it and get a written quote**

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.

[**Describe your problem **→](https://app369.com/contact/) [**All fixes**](https://app369.com/fix/)