This JavaScript strict mode error occurs when attempting to modify a property that has been marked as read-only, commonly through Object.freeze() or Object.defineProperty(). In React applications, this typically happens when directly mutating frozen state objects, props, or DOM properties.
This error is a JavaScript strict mode enforcement that prevents modification of properties marked as immutable. In strict mode, attempting to assign a value to a read-only property throws a TypeError, whereas in non-strict code the assignment would be silently ignored. In React applications, this error most commonly occurs when trying to directly mutate state objects or props that have been frozen (using Object.freeze()), when modifying properties defined with Object.defineProperty() without writable: true, or when attempting to assign values to inherently read-only DOM properties like the style object or window.event. The error serves as a safeguard to enforce immutability principles that are core to React's design. React expects state and props to be treated as immutable, and many libraries use Object.freeze() in development mode to catch accidental mutations early. This is particularly important in React's reconciliation process, where reference equality checks are used for performance optimization.
Check the error message to identify the exact property causing the issue. The error typically includes the property name:
TypeError: Cannot assign to read only property 'propertyName' of object '#<Object>'Use browser DevTools to inspect the object and verify its property descriptors:
const obj = { /* your object */ };
console.log(Object.getOwnPropertyDescriptor(obj, 'propertyName'));
// Check if writable: falseNever mutate React state or props directly. Instead, create a new copy:
// BAD - Direct mutation
this.state.user.name = 'John'; // Error!
// GOOD - Create new object
this.setState({
user: { ...this.state.user, name: 'John' }
});
// For arrays - use spread or array methods
// BAD
this.state.items.push(newItem); // Error!
// GOOD
this.setState({
items: [...this.state.items, newItem]
});For functional components with hooks:
const [user, setUser] = useState({ name: 'Jane', age: 25 });
// GOOD - spread operator creates new object
setUser({ ...user, name: 'John' });Don't assign strings directly to element.style. Use style.cssText or individual properties:
// BAD - This throws read-only error
element.style = "color: blue; font-size: 14px";
// GOOD - Use cssText
element.style.cssText = "color: blue; font-size: 14px";
// BETTER - Set individual properties
element.style.color = "blue";
element.style.fontSize = "14px";
// In React, use style object
<div style={{ color: 'blue', fontSize: '14px' }}>Content</div>If you've frozen an object and need to modify it, create a mutable copy:
const frozenObj = Object.freeze({ name: 'John', age: 30 });
// BAD
frozenObj.age = 31; // Error in strict mode!
// GOOD - Create mutable copy
const mutableCopy = { ...frozenObj };
mutableCopy.age = 31;
// For nested frozen objects
const deepCopy = JSON.parse(JSON.stringify(frozenObj));
deepCopy.age = 31;Note: Many React libraries freeze objects in development mode only. This helps catch bugs early without performance impact in production.
If using TypeScript with useRef and getting readonly errors, use the correct type:
// BAD - RefObject makes current readonly
const inputRef = useRef<HTMLInputElement>(null);
inputRef.current = someElement; // Error!
// GOOD - MutableRefObject allows assignment
const inputRef = useRef<HTMLInputElement | null>(null);
inputRef.current = someElement; // Works!
// Alternative - use as assertion if you know it won't be null
const inputRef = useRef<HTMLInputElement>(null!);If you control the object definition, ensure properties are writable:
const obj = {};
// Creating read-only property
Object.defineProperty(obj, 'name', {
value: 'John',
writable: false, // This causes the error
configurable: true
});
// Redefine as writable
Object.defineProperty(obj, 'name', {
value: 'John',
writable: true, // Now it can be modified
configurable: true
});
obj.name = 'Jane'; // Works!Check if property is configurable first:
const descriptor = Object.getOwnPropertyDescriptor(obj, 'name');
if (descriptor && descriptor.configurable) {
Object.defineProperty(obj, 'name', { writable: true });
}For IE11 compatibility issues with window.event:
// BAD - IE11 throws error in strict mode
window.event = customEvent;
// GOOD - Check browser and use polyfill
if (typeof window.event === 'undefined') {
// Modern browsers
document.dispatchEvent(customEvent);
} else {
// IE11 - use different approach
const evt = document.createEvent('Event');
evt.initEvent('custom', true, true);
document.dispatchEvent(evt);
}Consider using polyfills or updating to modern browsers if possible, as IE11 is no longer officially supported by Microsoft.
Development vs Production Behavior: Many React libraries (Redux, MobX, Immer) use Object.freeze() only in development mode to catch mutation bugs early without the performance overhead in production. This means errors might only appear during development, which is intentional to help you find bugs before deployment.
Immutability Libraries: Consider using libraries like Immer that make immutable updates easier with a mutable-looking API. Immer uses Proxies to track changes and produce immutable updates automatically.
Performance Considerations: While creating copies of objects might seem wasteful, React's reconciliation algorithm relies on reference equality checks for performance. Immutable updates enable shallow comparison (prevState !== nextState) which is much faster than deep equality checks.
Strict Mode in React: React's StrictMode component intentionally double-invokes certain functions in development to help detect side effects. This can make readonly errors more apparent if you're accidentally mutating objects.
Browser Compatibility: IE11 and old Edge versions are particularly strict about read-only properties compared to modern browsers. If targeting these browsers, test thoroughly in strict mode or consider transpilation strategies that avoid strict mode in legacy browsers.
Frozen Objects in State Management: When using state management libraries, frozen objects help enforce the unidirectional data flow pattern. Rather than disabling freezing, embrace immutable update patterns as they prevent entire classes of bugs related to unexpected state mutations.
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite