How to fix TypeError: Cannot assign to read-only property of object in React

ReactINTERMEDIATEMEDIUMUpdated Dec 10, 2025· 97 views

This error occurs in strict mode when attempting to modify a property that has been marked as non-writable, such as frozen objects, React props, or properties defined with Object.freeze() or Object.defineProperty().

Quick fix

Fixes TypeError

// Error will show something like:
// TypeError: Cannot assign to read-only property 'name' of object '#<Object>'

// Common culprits:
function MyComponent(props) {
  props.value = 'new value'; // ❌ Props are read-only
  return <div>{props.value}</div>;
}
  1. Identify the read-only property being modified
  2. Replace direct prop mutations with proper state management
  3. Create copies of frozen objects or arrays before modification
  4. Fix useRef readonly property errors in TypeScript
react — error
// Error will show something like:
// TypeError: Cannot assign to read-only property 'name' of object '#<Object>'
// Common culprits:
function MyComponent(props) {
props.value = 'new value'; // ❌ Props are read-only
return <div>{props.value}</div>;
}
TypeError: Cannot assign to read-only property of object

What this error means

This TypeError occurs exclusively in JavaScript's strict mode when code attempts to modify a property that has been explicitly marked as read-only or non-writable. In React applications, this commonly happens when developers try to mutate props directly, modify frozen objects, or change properties that were created with Object.freeze() or Object.defineProperty() with writable: false. Strict mode enforces immutability rules that would otherwise fail silently in non-strict code. React's ecosystem heavily relies on immutability principles, making this error particularly common when developers accidentally violate these patterns. The error serves as a protective mechanism to catch unintended mutations that could lead to hard-to-debug issues. In React, props are intentionally immutable - they're snapshots of data at a specific point in time. When this error appears, it's usually indicating that code is attempting to break React's unidirectional data flow by modifying data that should remain constant throughout a component's lifecycle.

Typical symptoms

  • TypeError thrown only when "use strict" is enabled or in ES6 modules
  • Error message specifically mentions "read-only property" with the property name
  • Code works in development but fails in production builds (which often enable strict mode)
  • Error occurs when trying to assign values to props directly in React components
  • Mutations to frozen objects or arrays cause immediate failures
  • useRef current property assignments fail with TypeScript errors about readonly properties

Common causes

  1. Attempting to directly mutate React props inside a component (props.value = newValue)
  2. Modifying objects or arrays that were frozen using Object.freeze()
  3. Assigning to properties defined with Object.defineProperty() where writable: false
  4. Trying to mutate state directly instead of using setState or state setter functions
  5. Modifying useRef with readonly current property (common TypeScript issue)
  6. Working with immutable libraries (Immutable.js, Immer) that return frozen structures
  7. Attempting to sort or modify arrays passed as props without creating copies first
  8. Mutating Redux state directly outside of reducers or without proper immutable patterns

How to fix "TypeError: Cannot assign to read-only property of object"

1Identify the read-only property being modified

Examine the error stack trace to find the exact line and property causing the issue:

javascript
// Error will show something like:
// TypeError: Cannot assign to read-only property 'name' of object '#<Object>'

// Common culprits:
function MyComponent(props) {
  props.value = 'new value'; // ❌ Props are read-only
  return <div>{props.value}</div>;
}

Check if you're modifying:
- React props directly
- Objects/arrays from Object.freeze()
- Properties with writable: false
- useRef.current in TypeScript

2Replace direct prop mutations with proper state management

In React, never mutate props. Use state and callbacks instead:

javascript
// ❌ Wrong - mutating props
function Counter(props) {
  props.count = props.count + 1;
  return <div>{props.count}</div>;
}

// ✅ Correct - use state for mutable values
function Counter({ initialCount }) {
  const [count, setCount] = useState(initialCount);

  const increment = () => {
    setCount(count + 1); // Proper state update
  };

  return (
    <div>
      <p>{count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

// ✅ Correct - callback to parent for prop changes
function ChildComponent({ value, onValueChange }) {
  return (
    <input
      value={value}
      onChange={(e) => onValueChange(e.target.value)}
    />
  );
}
3Create copies of frozen objects or arrays before modification

If you need to modify frozen data structures, clone them first:

javascript
// ❌ Wrong - sorting frozen array
function SortedList({ items }) {
  const sorted = items.sort(); // Fails if items is frozen
  return <ul>{sorted.map(item => <li key={item}>{item}</li>)}</ul>;
}

// ✅ Correct - create copy before sorting
function SortedList({ items }) {
  const sorted = [...items].sort(); // Spread creates new array
  return <ul>{sorted.map(item => <li key={item}>{item}</li>)}</ul>;
}

// For objects:
const frozenUser = Object.freeze({ name: 'John', age: 30 });

// ❌ Wrong
frozenUser.age = 31;

// ✅ Correct - create new object
const updatedUser = { ...frozenUser, age: 31 };

// Or use Object.assign
const updatedUser2 = Object.assign({}, frozenUser, { age: 31 });
4Fix useRef readonly property errors in TypeScript

When using useRef with TypeScript, include null in the type to make current mutable:

typescript
// ❌ Wrong - current is readonly
const inputRef = useRef<HTMLInputElement>(null);
inputRef.current = document.getElementById('input') as HTMLInputElement;
// Error: Cannot assign to 'current' because it is a read-only property

// ✅ Correct - union type with null makes it mutable
const inputRef = useRef<HTMLInputElement | null>(null);
inputRef.current = document.getElementById('input') as HTMLInputElement;

// For callbacks:
function MyComponent() {
  const callbackRef = useRef<(() => void) | null>(null);

  useEffect(() => {
    callbackRef.current = () => {
      console.log('Callback executed');
    };
  }, []);

  return <button onClick={() => callbackRef.current?.()}>Click</button>;
}
5Handle immutable library patterns correctly

When using libraries like Immer or Immutable.js with React Hook Form or similar libraries:

javascript
// react-hook-form example with Immer
import { useForm } from 'react-hook-form';
import produce from 'immer';

function FormComponent() {
  const { register, handleSubmit, setValue } = useForm();

  // ❌ Wrong - passing frozen object to onChange
  const handleChange = (frozenData) => {
    setValue('field', frozenData); // Fails with immutable data
  };

  // ✅ Correct - convert to plain object first
  const handleChange = (frozenData) => {
    const plainData = JSON.parse(JSON.stringify(frozenData));
    setValue('field', plainData);
  };

  // Or use Immer's produce correctly
  const updateData = (data) => {
    const newData = produce(data, draft => {
      draft.field = 'new value'; // Immer handles immutability
    });
    setValue('field', newData);
  };

  return <form onSubmit={handleSubmit(onSubmit)}>...</form>;
}
6Verify strict mode is intentional

Check if strict mode is necessary for your use case:

javascript
// Explicit strict mode
"use strict";

// ES6 modules are automatically in strict mode
import React from 'react';

// React.StrictMode in development
function App() {
  return (
    <React.StrictMode>
      <MyComponent />
    </React.StrictMode>
  );
}

React.StrictMode enables additional checks but doesn't cause this specific error. The TypeError comes from JavaScript's strict mode, which is enabled by:
- ES6 modules (import/export)
- "use strict" directive
- Class bodies (always strict)
- Production builds that transpile with strict mode

If the error only appears in production, ensure your development environment matches production's strict mode settings.

Advanced notes

Deep Freeze vs Shallow Freeze

Object.freeze() only performs a shallow freeze - nested objects remain mutable:

javascript
const user = Object.freeze({
  name: 'John',
  address: { city: 'NYC' }
});

user.name = 'Jane'; // ❌ Error in strict mode
user.address.city = 'LA'; // ✅ Works - nested object not frozen

// Deep freeze utility
function deepFreeze(obj) {
  Object.freeze(obj);
  Object.getOwnPropertyNames(obj).forEach(prop => {
    if (obj[prop] !== null
      && (typeof obj[prop] === "object" || typeof obj[prop] === "function")
      && !Object.isFrozen(obj[prop])) {
      deepFreeze(obj[prop]);
    }
  });
  return obj;
}

React StrictMode vs JavaScript Strict Mode

These are different concepts:
- React.StrictMode: Development helper that double-invokes effects to catch side effects
- JavaScript strict mode: Language feature that catches coding mistakes and "unsafe" actions

Performance Considerations

Object.freeze() has minimal performance impact but prevents optimizations that rely on object identity. In React:
- Frozen props can prevent unnecessary re-renders (referential equality)
- But they prevent in-place optimizations some libraries rely on
- Use judiciously - not all data needs to be frozen

ESLint Rules

Prevent these errors at compile time:

json
{
  "rules": {
    "react/no-direct-mutation-state": "error",
    "@typescript-eslint/prefer-readonly": "warn",
    "functional/no-let": "warn",
    "functional/immutable-data": "error"
  }
}

Redux DevTools and Frozen State

Redux DevTools may freeze state to detect mutations. If you see this error when DevTools are open but not otherwise, you're likely mutating Redux state:

javascript
// ❌ Wrong - mutating state
function reducer(state, action) {
  state.count++; // Error with DevTools
  return state;
}

// ✅ Correct - return new state
function reducer(state, action) {
  return { ...state, count: state.count + 1 };
}

Frequently asked questions

What does "TypeError" mean?
This TypeError occurs exclusively in JavaScript's strict mode when code attempts to modify a property that has been explicitly marked as read-only or non-writable. defineProperty() with writable: false. Strict mode enforces immutability rules that would otherwise fail silently in non-strict code.
How do I fix "TypeError"?
This error occurs in strict mode when attempting to modify a property that has been marked as non-writable, such as frozen objects, React props, or properties defined with Object.freeze() or Object.defineProperty().
What causes "TypeError"?
Attempting to directly mutate React props inside a component (props.value = newValue) Modifying objects or arrays that were frozen using Object.freeze() Assigning to properties defined with Object.defineProperty() where writable: false
Is the "TypeError" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading