A webkit bug that shipped in iOS 8 beta 5 and appears to have been partially included in the launch of iOS 8 and 8.1 is affecting many of our customers. It does not seem to impact all iOS8 uniformly; different versions of webkit seem to be involved.
The Error
The error will be recorded as:
TypeError: Attempted to assign to readonly property.
What’s Actually Happening
This is a pretty nasty bug in the WebKit JavaScript engine’s JIT compiler. When your code uses Object.create()
and runs in strict mode, the compiler gets confused during optimization and tries to assign properties to the prototype instead of the actual object. Since prototype properties are often readonly, boom—you get this error.
The bug is reported in WebKit as WebIDL attributes should be implemented as getters and setters on the prototype object and the specific iOS 8 issue as WebKit bug #138038. It only affects 32-bit ARM devices (iPhone 4S, 5, 5C, iPad 2, etc.) because the 64-bit processors use different optimization paths.
Frameworks Hit Hard
This bug wreaked havoc on popular JavaScript frameworks:
Ember.js apps would show white screens when rendering nested {{#each}}
loops. The framework’s mixin system relies heavily on prototype manipulation, which triggered the bug during template compilation. Check Ember issue #5606 for the gory details.
Angular 1.2.25 had problems with scope creation in rootScope.js
. Multiple property assignments like this.$$watchers = this.$$nextSibling = null
would fail on iOS 8. See Angular issue #9128.
Polymer apps crashed during startup because the Web Components polyfills tried to assign properties that the buggy JIT marked as readonly.
Solutions That Actually Work
Each framework encountered this differently, but here are the main workarounds:
Remove Strict Mode (Quick but Dirty)
The fastest fix is removing "use strict"
declarations from your code. In non-strict mode, the failed assignments just fail silently instead of throwing errors. Not ideal, but it works.
Framework Updates
- Ember: Upgrade to versions with iOS 8 compatibility patches, or use the
yapplabs/ember-ios8-fix
build - Angular: Upgrade to 1.3+ or use
angular.copy()
for deep object copying - Polymer: Update to newer polyfill versions that include workarounds
Alternative Object Creation
Avoid Object.create()
entirely by using constructor patterns:
// Instead of Object.create()
function SafeConstructor() {}
SafeConstructor.prototype = myPrototype;
var obj = new SafeConstructor();
Property Assignment Fallbacks
For bulletproof code, wrap property assignments in try-catch blocks:
try {
obj.property = value;
} catch(e) {
if (e.message.includes('readonly')) {
// Fallback assignment method
Object.defineProperty(obj, 'property', {
value: value,
writable: true
});
}
}
The Resolution
Apple fixed this in iOS 9 but never backported the fix to iOS 8. The bug was finally resolved in WebKit changeset r184960 in May 2015, but developers had to maintain workarounds until iOS 8 usage dropped significantly.
If you’re still seeing this error, check your framework version and consider the workarounds above. The good news is that this specific bug is mostly historical now, but understanding it helps when debugging similar JIT-related issues in other browsers.