Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

(iOS 8 GM iPhone5C) TypeError: Attempted to assign to readonly property #9128

Closed
HAKASHUN opened this issue Sep 17, 2014 · 163 comments
Closed

(iOS 8 GM iPhone5C) TypeError: Attempted to assign to readonly property #9128

HAKASHUN opened this issue Sep 17, 2014 · 163 comments

Comments

@HAKASHUN
Copy link
Contributor

I am using on iOS 8 GM(iPhone5C).
With this device, I am getting this error in this line(https://github.com/angular/angular.js/blob/master/src/ng/rootScope.js#L216)
But on iOS 8 GM(iPhone5S) and iOS 7.x (iPhone5C, iPhone5S), this error does not occur.

To resolve this error, I rewrote the code as follows:

$new: function(isolate) {
        var child;

        if (isolate) {
          child = new Scope();
          child.$root = this.$root;
          // ensure that there is just one async queue per $rootScope and its children
          child.$$asyncQueue = this.$$asyncQueue;
          child.$$postDigestQueue = this.$$postDigestQueue;
        } else {
          // Only create a child scope class if somebody asks for one,
          // but cache it to allow the VM to optimize lookups.
          if (!this.$$ChildScope) {
            this.$$ChildScope = function ChildScope() {
              this['$$watchers'] = this['$$nextSibling'] =
                  this['$$childHead'] = this['$$childTail'] = null;
              this['$$listeners'] = {};
              this['$$listenerCount'] = {};
              this['$id'] = nextUid();
              this['$$ChildScope'] = null;
            };
            this.$$ChildScope.prototype = this;
          }
          child = new this.$$ChildScope();
        }
        child['this'] = child;
        child['$parent'] = this;
        child['$$prevSibling'] = this.$$childTail;
        if (this.$$childHead) {
          this.$$childTail.$$nextSibling = child;
          this.$$childTail = child;
        } else {
          this.$$childHead = this.$$childTail = child;
        }
        return child;
      },

The situation has improved, but I do not understand the reason...

@Narretz
Copy link
Contributor

Narretz commented Sep 17, 2014

Which version of angular did you test? Does it appear simply by including angular or under specific circumstances (your app code)?

@HAKASHUN
Copy link
Contributor Author

I tested AngularJS v1.2.25.

My app code is below.

page template

...
<card-item-list ng-repeat="card in cards track by $index" data-card="card"></card-item-list>

card-item-list directive

...
var cardItemList = function() {
    var link = function(scope) {};
    return {
      restrict: 'E',
      replace: true,
      templateUrl: 'templates/card/directives/list-item.html',
      scope: {
        card: '=',
      },
      link: link
    };
  };
  cardItemList.$inject = [];
...
<div class="card--list__item">
  <div ng-class="{'card--list__item_state_check': card.isSelect}">
    <card-thumb data-card="card"></card-thumb>
  </div>
  <p class="card--list__item__detail fs_xxs">
    <span ng-if="card.parameter.attack > 0">{{card.parameter.attack}}<br>&nbsp</span>
    <span ng-if="card.parameter.defense > 0">{{card.parameter.defense}}<br>{{card.parameter.speed}}</span>
  </p>
</div>

card-thumb directive

...
var cardThumb = function() {
    return {
      restrict: 'E',
      replace: true,
      transclude: true,
      templateUrl: ''templates/card/directives/card-thumb.html',
      scope: {
        card: '=',
        opts: '=?'
      },
      link: function(scope, element){
      }
    };
  };
 cardThumb.$inject = [];
...
<figure class="thumb thumb_type_1">
  <img class="thumb__img" ng-src="{{card.image_path}}"  ng-if="card.master_id">
  <figcaption class="thumb__caption" ng-transclude></figcaption>
</figure>

@caitp
Copy link
Contributor

caitp commented Sep 26, 2014

@ChristianV could you please put together a http://plnkr.co/ or http://jsbin.com/ to reproduce this?

I'll see if I can repro this on my ipad or iphone 6 (but, from what you said, it sounds like I might not be able to :()

@christianvuerings
Copy link
Contributor

@caitp I think you meant to notify someone else.

@caitp
Copy link
Contributor

caitp commented Sep 26, 2014

yeah I meant @HAKASHUN, sorry

@disney007
Copy link

remove 'use strict' and try

@ssetem
Copy link

ssetem commented Oct 31, 2014

we get the same issue, and @HAKASHUN's code fixed the issue for us

shunjikonishi pushed a commit to shunjikonishi/angular.js that referenced this issue Nov 6, 2014
@shunjikonishi
Copy link

We get the same issue.

I applied @HAKASHUN's code to v1.2.26

shunjikonishi@b91f341

When I include angular.js, it works fine.
But with angular.min.js, it doesn't work.

I hope to fix this problem with both of normal and minified version.

@bennett000
Copy link

We have also experienced this error with several different iPads, all running iOS 8. I can get exact model numbers if anybody is interested. We have tried builds with Angular versions: 1.2.24, 1.3.0, and 1.3.1

@HAKASHUN's fix has worked at least in debug (non-minified) builds.

@shunjikonishi this is just a guess (I'm dealing with the same issue) but does your minifier perhaps do something like forcing dot notation? That would effectively undo this fix. I've tried one minification with uglify (2.4) and it broke the fix, and now I'm looking into my guess. Perhaps I can ask uglify to respect dot notation, or maybe I'm way off.

update

Is anyone else using $route?

Also @shunjikonishi in my case, uglifyjs was forcing dot notation, effectively undoing the fix. If you're using grunt/uglify it's something like: uglify: { options: { properties: false }}

@caitp
Copy link
Contributor

caitp commented Nov 6, 2014

could you make a quick reproduction of this? I'd like to see it with my phone

@bennett000
Copy link

@caitp I will see what I can do. I've got some unexpected work to take care of, but this is important, so hopefully I will have a plunker by the afternoon.

update

@caitp I made a plunker to attempt to reproduce this issue, and failed.

If anyone is interested in looking at my plunker attempt at reproducing, it's here: http://plnkr.co/edit/EPsxhO1OsD5MmnUyl50t?p=preview I started with a simple click updating a $scope, then tried $route changes (which is where I can consistently reproduce in my app), and then tried repeats, and a repeat in an ng-if.

I will put more time into this later.

@shunjikonishi
Copy link

@bennett000 Thank you for advise.

I just used output of grunt package command.

Now, I include uglify angular task in my project. It works fine.

There is one correction.
With grunt-contrib-uglify, its option format is like this.

uglify: {
    options: { 
        compress: {
            properties: false 
        }
    }
}

shunjikonishi pushed a commit to shunjikonishi/angular.js that referenced this issue Nov 7, 2014
@spencerwi
Copy link

This also appears to affect Angular v1.3.0; we've seen it on an iOS8 device in our office, but the page it's on hits the error inconsistently (something we're researching).

Applying @shunjikonishi 's patch causes the page not to break under those conditions, but also causes "undefined" to appear on the page in places it shouldn't, and not to be removed.

Perhaps not the most useful set of details, but this is the result of an initial investigation. We can dig deeper; just wanted to note that v1.3.0 is also affected.

@caitp
Copy link
Contributor

caitp commented Nov 7, 2014

hey guys, we're still waiting for a reproduction =)

@caitp
Copy link
Contributor

caitp commented Nov 7, 2014

(so please provide one)

@bennett000
Copy link

@caitp absolutely, reproducing the error consistently is essential.

What's odd is that I can reproduce this consistently in my application, as can others; yet I failed to reproduce in a plunker. I'm happy to keep working on reproducing this in an example, but I'd really like to get more details from other people who have this issue.

In our case:

  • Web app is "saved" to iOS home screen
  • Web app is run from iOS home screen
  • Web app breaks after a few $location.path() calls

iDevice model numbers known to be affected:

  • MD528C/A
  • MD516C/A
  • MF432C/A

I'm wondering if there is a difference if the application is run from the iOS home screen, as opposed to being run in iOS Safari, or in a WebView, or WKView; this has been the case in older iOS versions.

I will work more on a plunker, and I will also take the plunker code, and spin it into a self contained application so I can see if I can reproduce it when "saved" to the iOS home screen.

Again, any extra information anyone else has about their issues would be helpful.

update

Dropping the existing plunkr stuff I had done into a full blown iOS homescreen web app does not seem to have had any additional effect.

Is anyone else using any custom gestures, or doing anything special to avoid things like iOS's bounce scrolling?

@dmitriynosenko
Copy link

Removing the 'use strict'; solve the issue for me (iPhone 5C iOS 8.1).

@bennett000
Copy link

Over the last few weeks I continued to fail to reproduce this problem in a controlled environment, like a plunkr. On top of that, other workarounds, including removing 'use strict' do not help me. Obviously without a controlled reproduction of this issue there's nowhere to begin solving this problem. However it occurred to me that Angular ships with its own unit test suite; how do those tests perform on my devices?

  • Angular.js commit: 9a616ea
  • On Ubuntu 12.04, running Chromium 37.0.2062 all tests pass
  • On iOS 7.1.2, running mobile Safari 7.0.0, (Model MF432C/A) all tests pass
  • On iOS 8.1.1, running mobile Safari 8.0.0, (Model MD528C/A) one tests fails

Mobile Safari 8.0.0 (iOS 8.1.1) private mocks createMockStyleSheet should allow custom styles to be created and removed when the stylesheet is destroyed FAILED Expected '0px' to be '2px'. ~/Workspaces/angular.js/test/helpers/privateMocksSpec.js:23:47

My guess is that this failed test is unrelated.

Again, anyone with any suggestions on how to reproduce the iOS 8 readonly error would be helpful. I do know other frameworks have had similar issues with readonly property assignments in iOS8.x but they have not helped me reproduce. Here are the links that reference the similar issues some others have encountered

Other steps I've taken to mitigate this problem have been to comb over our entire source, and the source of every library we use to find anything that might set a property read only. This includes grepping for:

  • Object.create()
  • freeze
  • writable
  • configurable
  • defineProperty

Is there anything else that might make JavaScript throw a type error read only? Not being able to reproduce this is not helping my sanity.

@m3kka
Copy link

m3kka commented Dec 9, 2014

We are also running into this.
We were able to reproduce the problem only on the actual device (in our case IPhone 5C) with an IOS version prior to 8.1 (we're testing on 8.0.2 and the problem recurs continuously).

This is quite a serious issue, is there any known workaround?

(We're on Angular 1.3.6, updated today, problem still persists)

@pkozlowski-opensource
Copy link
Member

@m3kka did you manage to isolate the problem? It will be very hard to move on this one without narrowing it down first.

@m3kka
Copy link

m3kka commented Dec 9, 2014

Spent the afternoon looking for a way to reproduce the error in a controlled environment but still no solutions sadly.

I've expanded a bit the workaround of @HAKASHUN so if anyone needs a fast - notSoGood - fix this is what I did.

AngularJS ver. 1.3.6:

RootScope
https://github.com/angular/angular.js/blob/master/src/ng/rootScope.js#L208
From:

          if (!this.$$ChildScope) {
            this.$$ChildScope = function ChildScope() {
              this.$$watchers = this.$$nextSibling =
                  this.$$childHead = this.$$childTail = null;
              this.$$listeners = {};
              this.$$listenerCount = {};
              this.$id = nextUid();
              this.$$ChildScope = null;
            };

To:

          if (!this['$$ChildScope']) {
            this['$$ChildScope'] = function ChildScope() {
              this['$$watchers'] = this['$$nextSibling'] =
                  this['$$childHead'] = this['$$childTail'] = null;
              this['$$listeners'] = {};
              this['$$listenerCount'] = {};
              this['$id'] = nextUid();
              this['$$ChildScope'] = null;
            };

https://github.com/angular/angular.js/blob/master/src/ng/rootScope.js#L221
From:

        child.$parent = parent;
        child.$$prevSibling = parent.$$childTail;

To:

        child['$parent'] = parent;
        child['$$prevSibling'] = parent.$$childTail;

Compile
https://github.com/angular/angular.js/blob/master/src/ng/compile.js#L1375
From:

transcludedScope.$$transcluded = true;

To

transcludedScope['$$transcluded'] = true;

Until now I am not able to help you with more informations, will keep looking into the issue.

@Wasmoo
Copy link

Wasmoo commented Dec 10, 2014

I figured this one out. iOS dies on this line:

              this.$$watchers = this.$$nextSibling =
                  this.$$childHead = this.$$childTail = null;

When I broke this out into separate statements, I found the error was caused when this.$$watchers was assigned first. The following worked correctly:

              this.$$childTail = null;
              this.$$childHead = null;
              this.$$nextSibling = null;
              this.$$watchers = null;

I suspect iOS executes the order of the assignment incorrectly, causing the error. I don't know where else this syntax difference would cause errors, but I suspect it has far reaching implications.

@brunofranco
Copy link

@johgusta's solution solved my problem in angular 1.4.2

@atMari
Copy link

atMari commented Oct 12, 2015

@johgusta's solution appears to have solved our issues in angular 1.4.5

@shershen08
Copy link

+1, tried with 1.4.0, 1.4.6 same story. How I can intelligently patch Angular if I don't use webpack?

@lgalfaso
Copy link
Contributor

lgalfaso commented Nov 5, 2015

@code-tree
Copy link

Note, while reports are that it only affects IOS8, I now have a case of it occurring on IOS9.2 (despite using webkit-assign fix). Any ideas?

TypeError: Attempted to assign to readonly property.
Mozilla/5.0 (iPhone; CPU iPhone OS 9_2 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13C75 Safari/601.1

Will try removing 'use strict's once I have a device I can regularly test on.

@jacksonrayhamilton
Copy link
Contributor

@code-tree If you've run all JavaScript code on your site through webkit-assign and can still consistently reproduce that error, you should file a bug on our repository.

@astopo
Copy link

astopo commented Dec 22, 2015

+1, angular 1.3.6 & 1.4.8, ios 8.2

@code-tree
Copy link

@jacksonrayhamilton Retrying on a different friend's device running iOS 9.2 worked fine, so I can't reproduce it, but it did still occur on the device mentioned earlier (which I no longer have access to). So I guess I'll wait and see if anyone else reports anything.

@JeroenNelen
Copy link

JeroenNelen commented Jan 28, 2016

Hello everyone,

I have also, unfortunately, ran into this issue.
I'm still a bit dazzled because of the behaviour:

  • I do not get it on every page in my application
  • I do not get it all the time on that specific page, only about 50% of the time

Does anyone noticed that it only happens with specific code or with loading issues?

I will look into the solution @jacksonrayhamilton provided, allthough I'm not sure if this will be usable for my final build.

Kind regards,

@code-tree
Copy link

Yes, it first occurred for me after testing on a device for 30 minutes without any issues. All of a sudden it kept occurring on the index page, without anything being (noticeably) different to the previous 30 minutes...

@JeroenNelen
Copy link

JeroenNelen commented Feb 1, 2016

Hello everyone,
I have noticed that it, for some reason, in my case seems to be related to the usage of ng-if's.
I use ng-if's to hide my pages until I have all my back-end calls done in order to make sure that all the data used by the directives is available before loading them.
Removing these ng-if's, it seems that I no longer get the readOnly errors (tested about 20 times).
Did anyone else noticed this?

Are there any negative side-effects for using @jacksonrayhamilton his solution? I am currently using angular 1.4.7.

@jacksonrayhamilton
Copy link
Contributor

@JeroenNelen While it's possible ngIf could be a culprit, I think it's more likely that the ngIf prevented or triggered some other code that was a culprit. As for the efficacy of the solution, we use an AST to transform and fix the code, so it should be pretty precise. We haven't had any problems using it in our production build and we have no open issues currently.

@JeroenNelen
Copy link

@jacksonrayhamilton Thanks for your reply. I will test to see if the issue still occurs after these changes, if it indeed occurs, I think the only solution will be to use your package (nice job on it by the way) :).
The weird thing is that I cannot get the error to occur on any other page, only on these specific pages, therefor I was meddling with the code on those pages to see if I could prevent the error locally (rather than adjusting anguluar.js).

@quochuy
Copy link

quochuy commented Feb 9, 2016

@jacksonrayhamilton Hi, is there a way to use your tool with Grunt?

@jacksonrayhamilton
Copy link
Contributor

var webkitAssign = require('webkit-assign');
module.exports = function(grunt) {
  grunt.registerTask('webkitAssign', function() {
    var file = 'build/scripts.js';
    var code = grunt.file.read(file);
    var transformed = webkitAssign(code);
    grunt.file.write(file, transformed);
  });
};

Or for better integration, maybe you'd like to submit a plugin to our repository? :-)

@spenoir
Copy link

spenoir commented Feb 16, 2016

We found a bug with angular-translate and ng-show on iOS8. removing ng-show in favour of ng-if fixes the issue. Also issue if parent has ng-show. ng-hide no doubt has an issue too!

@lesleychard
Copy link

@jacksonrayhamilton Thank you! Utility worked flawlessly. Problem is no longer persisting in iOS 8.3 / iPhone 5, AngularJS 1.4.9. Hours of headache later, you have made my day.

@jakub-g
Copy link

jakub-g commented Feb 23, 2016

@spenoir I think you're talking about a different bug regarding ng-show / ng-hide:
#13380 (comment)

@esetnik
Copy link

esetnik commented May 9, 2016

I just encountered the same issue. Will try the webkit-assign fix and report back.

@gkalpak
Copy link
Member

gkalpak commented Jun 1, 2016

Since this is a bug in WebKit, which has been fixed, there is a work-around and we don't have a clear reproduction to investigate further, this is not actionable on our part.
Closing...

@celle886
Copy link

@code-tree i ran into the same issue with the same description (iOS 9, appearing after long usage time). How do you fix your app?

@code-tree
Copy link

@celle886 No idea, sorry :)

It seems like webkit-assign helps, but I couldn't reliably reproduce the problem.

@mpiasta-ca
Copy link

Just came across this issue in our web app with Angular 1.4.8 when using iPod/iPhone 8.4.1 on Safari 8.0. Thanks for whoever was first to suggest webkit-assign. We used webkit-assign/gulp and that solved a problem that has been ghosting/plaguing us for 6+ months.

@TiagoSilvaPereira
Copy link

I have this issue using Angular 2 (with Ionic 2) in the iPhone 6s / iOS 9.2 simulator. The message is "Exception: TypeError: Attempted to assign to readonly property" I've tried the @jacksonrayhamilton webkit-assign solution, but this does not seem to work with Angular 2 (I've tried in the final app.bundle.js file).

Someone have an ideia how to fix this problem?

Thanks!

@Narretz
Copy link
Contributor

Narretz commented Dec 15, 2016

@TiagoSilvaPereira Please open an issue about this on the https://github.com/angular/angular repo. This repo here is only for the 1.x branch

@TiagoSilvaPereira
Copy link

TiagoSilvaPereira commented Dec 16, 2016

Thanks @Narretsz, i've solved this problem removing all "use strinct" from my code.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests