Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

135 deviceType must be specified in this operation #203

Closed
alexblack opened this issue Oct 20, 2015 · 55 comments · Fixed by #208
Closed

135 deviceType must be specified in this operation #203

alexblack opened this issue Oct 20, 2015 · 55 comments · Fixed by #208
Labels
type:bug Impaired feature or lacking behavior that is likely assumed

Comments

@alexblack
Copy link

A lot of my users encounter this error, I can't repro it, not sure what is going on. I'm using SDK 1.10.3. I first opened this issue on June 4th:

https://developers.facebook.com/bugs/903903186334036/

http://crashes.to/s/8a6fe6eb94f

"Failed to save parse installation: 135"

java.lang.Exception: com.parse.ph: deviceType must be specified in this operation
       at com.aadhk.woinvoice.util.ParseInit$2.then(ProGuard:163)
       at com.aadhk.woinvoice.util.ParseInit$2.then(ProGuard:156)
       at bolts.Task$15.run(ProGuard:825)
       at bolts.BoltsExecutors$ImmediateExecutor.execute(ProGuard:105)
       at bolts.Task.completeAfterTask(ProGuard:816)
       at bolts.Task.access$200(ProGuard:32)
       at bolts.Task$11.then(ProGuard:621)
       at bolts.Task$11.then(ProGuard:618)
       at bolts.Task.runContinuations(ProGuard:861)
       at bolts.Task.access$600(ProGuard:32)
       at bolts.Task$TaskCompletionSource.trySetError(ProGuard:932)
       at bolts.Task$TaskCompletionSource.setError(ProGuard:959)
       at bolts.Task$15$1.then(ProGuard:840)
       at bolts.Task$15$1.then(ProGuard:829)
       at bolts.Task$14.run(ProGuard:784)
       at bolts.BoltsExecutors$ImmediateExecutor.execute(ProGuard:105)
       at bolts.Task.completeImmediately(ProGuard:775)
       at bolts.Task.access$100(ProGuard:32)
       at bolts.Task$10.then(ProGuard:567)
       at bolts.Task$10.then(ProGuard:564)
       at bolts.Task.runContinuations(ProGuard:861)
       at bolts.Task.access$600(ProGuard:32)
       at bolts.Task$TaskCompletionSource.trySetError(ProGuard:932)
       at bolts.Task$TaskCompletionSource.setError(ProGuard:959)
       at bolts.Task$15$1.then(ProGuard:840)
       at bolts.Task$15$1.then(ProGuard:829)
       at bolts.Task$14.run(ProGuard:784)
       at bolts.BoltsExecutors$ImmediateExecutor.execute(ProGuard:105)
       at bolts.Task.completeImmediately(ProGuard:775)
       at bolts.Task.access$100(ProGuard:32)
       at bolts.Task$10.then(ProGuard:567)
       at bolts.Task$10.then(ProGuard:564)
       at bolts.Task.runContinuations(ProGuard:861)
       at bolts.Task.access$600(ProGuard:32)
       at bolts.Task$TaskCompletionSource.trySetError(ProGuard:932)
       at bolts.Task$TaskCompletionSource.setError(ProGuard:959)
       at bolts.Task$15$1.then(ProGuard:840)
       at bolts.Task$15$1.then(ProGuard:829)
       at bolts.Task$14.run(ProGuard:784)
       at bolts.BoltsExecutors$ImmediateExecutor.execute(ProGuard:105)
       at bolts.Task.completeImmediately(ProGuard:775)
       at bolts.Task.continueWith(ProGuard:574)
       at bolts.Task.continueWith(ProGuard:585)
       at bolts.Task$15.run(ProGuard:829)
       at bolts.BoltsExecutors$ImmediateExecutor.execute(ProGuard:105)
       at bolts.Task.completeAfterTask(ProGuard:816)
       at bolts.Task.access$200(ProGuard:32)
       at bolts.Task$11.then(ProGuard:621)
       at bolts.Task$11.then(ProGuard:618)
       at bolts.Task.runContinuations(ProGuard:861)
       at bolts.Task.access$600(ProGuard:32)
       at bolts.Task$TaskCompletionSource.trySetError(ProGuard:932)
       at bolts.Task$TaskCompletionSource.setError(ProGuard:959)
       at bolts.Task$15$1.then(ProGuard:840)
       at bolts.Task$15$1.then(ProGuard:829)
       at bolts.Task$14.run(ProGuard:784)
       at bolts.BoltsExecutors$ImmediateExecutor.execute(ProGuard:105)
       at bolts.Task.completeImmediately(ProGuard:775)
       at bolts.Task.access$100(ProGuard:32)
       at bolts.Task$10.then(ProGuard:567)
       at bolts.Task$10.then(ProGuard:564)
       at bolts.Task.runContinuations(ProGuard:861)
       at bolts.Task.access$600(ProGuard:32)
       at bolts.Task$TaskCompletionSource.trySetError(ProGuard:932)
       at bolts.Task$TaskCompletionSource.setError(ProGuard:959)
       at bolts.Task$15$1.then(ProGuard:840)
       at bolts.Task$15$1.then(ProGuard:829)
       at bolts.Task$14.run(ProGuard:784)
       at bolts.BoltsExecutors$ImmediateExecutor.execute(ProGuard:105)
       at bolts.Task.completeImmediately(ProGuard:775)
       at bolts.Task.access$100(ProGuard:32)
       at bolts.Task$10.then(ProGuard:567)
       at bolts.Task$10.then(ProGuard:564)
       at bolts.Task.runContinuations(ProGuard:861)
       at bolts.Task.access$600(ProGuard:32)
       at bolts.Task$TaskCompletionSource.trySetError(ProGuard:932)
       at bolts.Task$TaskCompletionSource.setError(ProGuard:959)
       at bolts.Task$15$1.then(ProGuard:840)
       at bolts.Task$15$1.then(ProGuard:829)
       at bolts.Task$14.run(ProGuard:784)
       at bolts.BoltsExecutors$ImmediateExecutor.execute(ProGuard:105)
       at bolts.Task.completeImmediately(ProGuard:775)
       at bolts.Task.continueWith(ProGuard:574)
       at bolts.Task.continueWith(ProGuard:585)
       at bolts.Task$15.run(ProGuard:829)
       at bolts.BoltsExecutors$ImmediateExecutor.execute(ProGuard:105)
       at bolts.Task.completeAfterTask(ProGuard:816)
       at bolts.Task.access$200(ProGuard:32)
       at bolts.Task$11.then(ProGuard:621)
       at bolts.Task$11.then(ProGuard:618)
       at bolts.Task.runContinuations(ProGuard:861)
       at bolts.Task.access$600(ProGuard:32)
       at bolts.Task$TaskCompletionSource.trySetError(ProGuard:932)
       at bolts.Task$TaskCompletionSource.setError(ProGuard:959)
       at bolts.Task$15$1.then(ProGuard:840)
       at bolts.Task$15$1.then(ProGuard:829)
       at bolts.Task$14.run(ProGuard:784)
       at bolts.BoltsExecutors$ImmediateExecutor.execute(ProGuard:105)
       at bolts.Task.completeImmediately(ProGuard:775)
       at bolts.Task.continueWith(ProGuard:574)
       at bolts.Task.continueWith(ProGuard:585)
       at bolts.Task$15.run(ProGuard:829)
       at bolts.BoltsExecutors$ImmediateExecutor.execute(ProGuard:105)
       at bolts.Task.completeAfterTask(ProGuard:816)
       at bolts.Task.access$200(ProGuard:32)
       at bolts.Task$11.then(ProGuard:621)
       at bolts.Task$11.then(ProGuard:618)
       at bolts.Task.runContinuations(ProGuard:861)
       at bolts.Task.access$600(ProGuard:32)
       at bolts.Task$TaskCompletionSource.trySetError(ProGuard:932)
       at bolts.Task$TaskCompletionSource.setError(ProGuard:959)
       at bolts.Task$15$1.then(ProGuard:840)
       at bolts.Task$15$1.then(ProGuard:829)
       at bolts.Task$14.run(ProGuard:784)
       at bolts.BoltsExecutors$ImmediateExecutor.execute(ProGuard:105)
       at bolts.Task.completeImmediately(ProGuard:775)
       at bolts.Task.continueWith(ProGuard:574)
       at bolts.Task.continueWith(ProGuard:585)
       at bolts.Task$15.run(ProGuard:829)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
       at java.lang.Thread.run(Thread.java:818)
Caused by: com.parse.ph: deviceType must be specified in this operation
       at com.parse.ParseRequest.onResponseAsync(ProGuard:301)
       at com.parse.ParseRESTCommand.onResponseAsync(ProGuard:288)
       at com.parse.ParseRequest$3.then(ProGuard:151)
       at com.parse.ParseRequest$3.then(ProGuard:147)
       at bolts.Task$15.run(ProGuard:825)
       at bolts.BoltsExecutors$ImmediateExecutor.execute(ProGuard:105)
       at bolts.Task.completeAfterTask(ProGuard:816)
       at bolts.Task.continueWithTask(ProGuard:628)
       at bolts.Task.continueWithTask(ProGuard:639)
       at bolts.Task$13.then(ProGuard:731)
       at bolts.Task$13.then(ProGuard:719)
       at bolts.Task$15.run(ProGuard:825)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
       at java.lang.Thread.run(Thread.java:818)

Here is a snippet of my code in this stack trace:

public Task<ParseInstallation> initParseInstallation() {
    final TimingLogger timings = new TimingLogger(TAG, "initParseInstallation");
    Log.d(TAG, "initParseInstallation");
    try {
      final ParseInstallation installation = ParseInstallation.getCurrentInstallation();
      installation.put("flavor", BuildConfig.FLAVOR);
      installation.put("accountId", accountId);
      installation.put("user", ParseUser.getCurrentUser());
      try {
        installation.put("androidId", Settings.Secure.getString(ctx.getContentResolver(), Settings.Secure.ANDROID_ID));
        installation.put("android", String.format("%s (%s %s)", Build.VERSION.RELEASE, Build.VERSION.CODENAME, Build.VERSION.INCREMENTAL));
        installation.put("device", String.format("%s (%s)", DeviceUtils.getDeviceName(), Build.HARDWARE));
        installation.put("abi", Build.CPU_ABI);
        installation.put("syncEnabled", Syncer.syncEnabled(ctx));
        installation.increment("appStart");
      } catch (Exception e) {
        App.err(ctx, "Failed to set properties on installation", e);
      }

      if (installation.containsKey("GCMSenderId"))
        installation.remove("GCMSenderId");

      timings.addSplit("setInstall");

      return installation.saveInBackground().continueWithTask(new Continuation<Void, Task<ParseInstallation>>() {
        @Override
        public Task<ParseInstallation> then(Task<Void> task) throws Exception {
          timings.addSplit("onInstall");
          if (task.isFaulted()) {
            if (task.getError() instanceof ParseException) {
              ParseException e = (ParseException) task.getError();
              App.err(ctx, "Failed to save parse installation: " + e.getCode(), new Exception(e));
            } else {
              App.err(ctx, "Failed to save parse installation", new Exception(task.getError()));
            }
            return Task.forError(task.getError());
          } else {
            Log.d(TAG, "Successfully initialized parseInstallation: " + installation.getObjectId());
            return Task.forResult(installation);
          }
        }
      });
    } catch (Exception e) {
      App.err(ctx, "Failed to setup parse installation", e);
      return Task.forError(e);
    }
  }
@grantland
Copy link
Contributor

This looks to be a valid bug!

The only the situation where deviceType wouldn't be set would be if the SDK doesn't think the current ParseInstallation is current here. It also looks like there could be a race condition where two ParseInstallations could be created and returned from ParseInstallation.getCurrentInstallation() here.

We won't be able to fully guarantee it'll resolve your issue since there isn't a stable repro for your situation, but it'll be better than nothing.

@grantland grantland added the type:bug Impaired feature or lacking behavior that is likely assumed label Oct 20, 2015
@alexblack
Copy link
Author

Great - does that mean you (or someone) will attempt a fix?

Is there anything I can do in the meantime to work around this? If the parseInstallation doesn't get saved then I can't send push notifications.

@grantland grantland self-assigned this Oct 21, 2015
@grantland
Copy link
Contributor

Sorry, ran off to a meeting before assigning myself.

TL;DR: There's no workaround, but the problem isn't as bad as you think.

If the above is correct, there are two different "current" ParseInstallations in the process on first app launch since no "current" ParseInstallation exists on disk. One is in your code's context where you're adding custom information and the other is in the SDK's context where it's registering GCM. Only one can be "current" and both have equal probability of being "current".

Right now we only have reports of failures from your code's context and it's plausible that the on in the SDK fails as well, but only one or the other and not both. Therefore failure cases will result in either the GCM registration information will be persisted or your custom information will be persisted, but a ParseInstallation will always get persisted on disk. This ParseInstallation on disk will then be read on next app launch and any missing data will be persisted to Parse since the on disk ParseInstallation will definitely have deviceToken, as long as your custom code allows this.

In the end, the probability of a device not having a GCM registration information after the first launch is very low and nonexistent upon relaunch.

@alexblack
Copy link
Author

That sounds promising. But a lot of my users won't have a relaunch, eg
they are just kicking the tires, they might stick around if they like the
app and it works well
On Oct 20, 2015 5:34 PM, "Grantland Chew" [email protected] wrote:

Sorry, ran off to a meeting before assigning myself.

TL;DR: There's no workaround, but the problem isn't as bad as you think.

If the above is correct, there are two different "current"
ParseInstallations in the process on first app launch since no "current"
ParseInstallation exists on disk. One is in your code's context where
you're adding custom information and the other is in the SDK's context
where it's registering GCM. Only one can be "current" and both have equal
probability of being "current".

Right now we only have reports of failures from your code's context and
it's plausible that the on in the SDK fails as well, but only one or the
other and not both. Therefore failure cases will result in either the GCM
registration information will be persisted or your custom information will
be persisted, but a ParseInstallation will always get persisted on disk.
This ParseInstallation on disk will then be read on next app launch and
any missing data will be persisted to Parse since the on disk
ParseInstallation will definitely have deviceToken, as long as your
custom code allows this.

In the end, the probability of a device not having a GCM registration
information after the first launch is very low and nonexistent upon
relaunch.


Reply to this email directly or view it on GitHub
#203 (comment)
.

@grantland
Copy link
Contributor

If that's the case, a possible workaround is to add your own retry logic from fetching the "current" ParseInstallation pointer, adding all your properties, and saving if the error code is 135.

@alexblack
Copy link
Author

Cool, I'll try that. Just checking I understand - do I just need to retry the same logic I already have? or does the 2nd attempt need to do something different?

@grantland
Copy link
Contributor

Same thing, I just wanted to reiterate that you need to make sure you operate on a fresh value returned from ParseInstallation.getCurrentInstallation()

@alexblack
Copy link
Author

Gotcha, thanks!

@alexblack
Copy link
Author

Do you know when the next SDK release might be so I can try this out? Or, do you ever publish interim binaries I could try?

@alexblack
Copy link
Author

Hmm, I'm not convinced this is the issue. I have one user who has had this error 298 times, ParseInstallation KSuNvq8VWj. He first saw the issue July 11th when he installed

msg Failed to save parse installation: 135 
ex  at least one ID field (installationId,deviceToken) must be specified in this operation 
stacktrace  com.parse.nc: at least one ID field (installationId,deviceToken) must be specified in this operation at com.parse.mp.a(ProGuard:391) at com.parse.me.a(ProGuard:197) at com.parse.ms.b(ProGuard:258) at com.parse.ms.a(ProGuard:254) at a.q.run(ProGuard:796) at a.g.execute(ProGuard:105) at a.k.d(ProGuard:787) at a.k.b(ProGuard:599) at a.k.b(ProGuard:610) at a.o.b(ProGuard:702) at a.o.a(ProGuard:690) at a.q.run(ProGuard:796) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) at java.lang.Thread.run(Thread.java:818)  
errid   c5e38848-cc5a-43ec-a6f2-7fef6a28e643 
name    error 

He gets the error when trying to save objects that reference his installation too (this error here happened today using the latest version of my app which uses the latest parse sdk)

msg Failed to saved parseMsg for msgRemoteId 9093de37-3392-4f19-a85b-6fc9a4047c45 
ex  com.parse.ph: deviceType must be specified in this operation 
stacktrace  java.lang.Exception: com.parse.ph: deviceType must be specified in this operation at com.aadhk.woinvoice.util.ap.b(ProGuard:472) at com.aadhk.woinvoice.util.ap.a(ProGuard:466) at a.u.run(ProGuard:825) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) at java.lang.Thread.run(Thread.java:818) Caused by: com.parse.ph: deviceType must be specified in this operation at com.parse.oz.a(ProGuard:301) at com.parse.ol.a(ProGuard:288) at com.parse.pc.b(ProGuard:151) at com.parse.pc.a(ProGuard:147) at a.u.run(ProGuard:825) at a.h.execute(ProGuard:105) at a.n.d(ProGuard:816) at a.n.b(ProGuard:628) at a.n.b(ProGuard:639) at a.s.b(ProGuard:731) at a.s.a(ProGuard:719) ... 4 more  
errid   40f12282-a344-4dc0-98f7-593f5ecc6920 
name    error 
appversion  0.1.171 

This doesn't seem to line up with your description of a race condition that goes away on 2nd app launch.

@alexblack
Copy link
Author

Just to add some context: this is the most prevalent exception I see in my app. Its happened 6,623 times to 834 users in the last 10 days. 834 users is not that many for my app, but its not nothing.

@alexblack
Copy link
Author

Is there any work around for my users who have this after months still? Can I explicitly add the deviceType value to the ParseInstallation myself?

@alexblack
Copy link
Author

@grantland any thoughts?

@grantland
Copy link
Contributor

Do you know when the next SDK release might be so I can try this out? Or, do you ever publish interim binaries I could try?

Yes, we have a snapshot build going for each commit that's published on Sonatype's snapshots repository.

Is there any work around for my users who have this after months still? Can I explicitly add the deviceType value to the ParseInstallation myself?

Not really since the error is coming from a new ParseInstallation instance that hasn't been persisted to Parse yet, but we'll try to have a new release by the end of the week.

@alexblack
Copy link
Author

I was talking about modifying my app's code to set the deviceType on the ParseInstallation when it saves it... wouldn't that solve the issue? My app saves the ParseInstallation on each startup, and some of my users have been hitting this issue on every startup for months.

@grantland
Copy link
Contributor

Unfortunately deviceType is a protected field and cannot be modified by the SDK. We're aiming to have a release by the end of next week.

@alexblack
Copy link
Author

Great. I look forward to trying the new release.

On Wed, Nov 4, 2015 at 5:51 PM, Grantland Chew [email protected]
wrote:

Unfortunately deviceType is a protected field and cannot be modified by
the SDK. We're aiming to have a release by the end of next week.


Reply to this email directly or view it on GitHub
#203 (comment)
.

@alexblack
Copy link
Author

Any update on the release?

@alexblack
Copy link
Author

hey @grantland two other questions:

  1. Will the fix solve the issue for my existing users who currently have this problem?
  2. Are you still confident the PR addresses this issue given the contradiction in the description of the bug (race condition that will go away on second app launch) vs my data showing users experience this bug over and over again after many months of app usage

@grantland
Copy link
Contributor

Trying to get a release out today.

  1. Yes it should
  2. I believe so as there shouldn't be any issues with the current ParseInstallation.

@alexblack
Copy link
Author

Great!

@alexblack
Copy link
Author

hey @grantland to help me understand #1 better (just above), how will things get fixed for users who have experienced this for ages?

I'm looking at a user who installed the app in April, who first experienced the issue in May or June, recently updated to the latest build of my app and is still experiencing the issue.

It seems unlikely their device is facing a race condition every time the app is started, so I'm concerned the problem with the missing deviceType will persist once the race condition is fixed.

Her installation is already saved on Parse, with id QqFs9jxgVX, here: https://www.parse.com/apps/invoice-maker/collections#class/_Installation/p0

Thinking this over, it looks like the app was able to create and save the installation normally until Parse SDK 1.9.2 (we see parse version 1.9.1 on her installation), and which point it could never save it again, despite many app starts, upgrades etc, and despite me downgrading from 1.9.2 back to 1.9.1 in my app (and later upgrading to 1.10.3)

@grantland
Copy link
Contributor

With the current information on hand the race condition is the only way I can see something like this happening from the SDK. Otherwise, I could see this could be coming from the persisted ParseInstallation on disk being corrupted/modified externally or the server incorrectly throwing this error, etc., but we cannot be sure unless we're able to reproduce this on a instrumented device.

As to why your specific user's ParseInstallation is in this specific state, it's hard for me to determine since I'm not familiar with the logic of your application, error reporting, etc. In general use cases, we do not automatically update the ParseInstallation object on new app/sdk updates or else that will cause unnecessary spikes in your req/s when you release an update.

@alexblack
Copy link
Author

My app attempts to save the ParseInstallation on each startup. I've shared what I think is all the relevant code.

I'm simply asking you to walk me through what you meant when you said "1. Yes it should" above. I gave a specific example to help keep the discussion grounded.

I think the theory you put forward was a race condition that would happen once the first time ParseInstallation.current was accessed, and that caused the issue.

From what little I know of your SDK and platform, that doesn't seem to line up with what I'm seeing. I'm just looking to you for input here, am I missing something, maybe the theory does line up, or, if it doesn't, then the issue ls likely not resolved.

I've only been facing the issue since June now :)

@alexblack
Copy link
Author

"but we cannot be sure unless we're able to reproduce this on a instrumented device."

Unfortunately I don't have any idea how to reproduce these Parse bugs, I had hoped that you could offer some insight there.

I'd be happy to add some instrumentation to my code to help narrow this down. I did that as requested back in June when I first opened the bug.

@alexblack
Copy link
Author

Unrelated: it'd be awesome if you guys included the exception code in the exception messages, so that when they are logged to tools like Crashlytics they are visible.

Even better would be separate exceptions classes per type of exception. I have a lot of code checks instanceof ParseException, then casts it, then checks the code.

@alexblack
Copy link
Author

Just saw a user fail to save their installation with the latest SDK. See attached. From previously logged events I see his installation's objectId is 0VfKnz2zif. This person has been a user since April. The fact that objectId is missing from the screenshot event means that the return value from installation.getObjectId() was null.

The app tried to save the installation a second time with the recently added retry code, and it failed in the same manner.

screenshot 2015-11-13 10 34 45

msg deviceType must be specified in this operation 
createdat    
abtest  navbar 
code    135 
name    installation.save-failed 
appversion  0.1.178 
installationid  d4a327d3-2ecf-4fb7-a177-c37edb238321 
idx 17 
devicetype  android 
updatedat   Sun May 03 18:42:51 MESZ 2015

Here is a json dump of the installation currently at Parse:

{
        "abi": "armeabi-v7a",
        "accountId": "94f6fa6d443a41a5b827603e9f067f3e",
        "android": "4.4.2 (REL T535XXU1ANK1)",
        "androidId": "824b8c636243bd37",
        "appIdentifier": "com.aadhk.woinvoice",
        "appName": "Rechnung ohne Mühe",
        "appStart": 20,
        "appVersion": "0.1.104",
        "createdAt": "2015-04-02T09:23:36.681Z",
        "device": "Samsung SM-T535 (qcom)",
        "deviceToken": "APA91bGvrN6NXd0o7C2CUoZcI9amaIIlYz0I8fPBcQ01-aYNEMZpbPJDceW58sGrZJ2my2iD6kiopgaPgf0Stu8ne3Heom6vRxGv0IBadq6h3bC-tdVqsTRB1qeIFDYzHB9XvQIQa9TNW80Z4nU1J4tBB2JMpoVOBA",
        "deviceTokenLastModified": 1430363864000,
        "deviceType": "android",
        "flavor": "free",
        "heartbeat": 20,
        "installationId": "d4a327d3-2ecf-4fb7-a177-c37edb238321",
        "objectId": "0VfKnz2zif",
        "parseVersion": "1.9.1",
        "pushType": "gcm",
        "syncEnabled": true,
        "timeZone": "Europe/Berlin",
        "updatedAt": "2015-05-03T16:42:51.981Z",
        "user": {
            "__type": "Pointer",
            "className": "_User",
            "objectId": "gxtQw0sHcx"
        }
    }

@alexblack
Copy link
Author

@grantland any thoughts? Should we re-open this if its still happening?

@wangmengyan95 wangmengyan95 reopened this Nov 17, 2015
@wangmengyan95
Copy link
Contributor

Hi @alexblack, I have reopened this issue. It seems our previous patch does not fix your issue. I will try my best to walk through our codebase again to see what we can find. I will update this issue if we need some more information from your side. objectId is null is very helpful.

@alexblack
Copy link
Author

Great. It does seem really odd to me that the ParseInstallation in the Android code and the ParseInstallation on parse.com both have deviceType set, but that the error is "deviceType must be specified in this operation".

What could be going on there?

@alexblack
Copy link
Author

It might be worth looking at what changed from 1.9.1 to 1.9.2, it looks to me like many installations never saved again after the user upgraded to a version of the app that used 1.9.2.

@wangmengyan95
Copy link
Contributor

Hi @alexblack, thanks for the clue. I will take a look at the diff between 1.9.2 and 1.9.1.

@alexblack
Copy link
Author

any update?

@alexblack
Copy link
Author

hi @wangmengyan95 any update here? This continues to affect my users. Is there some way I can just clear out their existing installation on the client so that they can start a new one?

@alexblack
Copy link
Author

Bump. This is still the most prevalent exception my users face in my app.

@grantland
Copy link
Contributor

From your logging I can see that objectId is unset, deviceType is set, and installationId is set to something that matches a ParseInstallation on your backend. This means that the ParseInstallation object you're saving is a new object instance with an installationId that's read from disk and deviceType is dirty, which means that:

  1. The issue of multiple ParseInstallation installations in a single process is not an issue anymore since deviceType is now being set.
  2. Either a new ParseInstallation instance is being created even though one has already been created on the backend with the same installationId or there's a overlap with installationId generation. This seems to be related to to Installation fails to save: SQLiteConstraintException #266 and should be discussed there.
  3. There's a possible backend issue where it's responding with that error even though deviceType has been set. I recommend opening up a backend ticket at http://parse.com/help to resolve this.

Since 1/ is resolved, 2/ is being discussed in #266, and 3/ is not related to the SDK, I'll be closing this issue.

@alexblack
Copy link
Author

I've never seen deviceType not set, I've captured it before and after upgrading the SDK and its always set on both client and server.

Responding to your points:

  1. Nothing changed here, deviceType was never not set (whenver I observed it), so I am not following.
  2. Great.
  3. It sounds like you're describing this issue... that deviceType is set but I get this exception when saving installations. I've indicated I think something is broken/wrong with the local data that some users have, that happened between 1.9.1 and 1.9.2. I don't think the backend team are the right people to talk about that, do you?

@alexblack
Copy link
Author

Hundreds of my users still face this issue, any chance you could respond to my response above? Thanks @grantland

@grantland
Copy link
Contributor

  1. This was referencing my first comment, where multiple instances of current ParseInstallation could occur. You wouldn't be able to detect it without actually debugging the application.

If this issue is still occurring, we'd need to be able to reproduce this in order to determine if it's a backend issue or SDK issue. Another thing you can do is to to verify yourself with network monitoring or ParseInterceptors whether or not a deviceToken is being sent by the client, but is still receiving the error.

@alexblack
Copy link
Author

Yes it is still occurring. Wouldn't it simply be a matter of finding some of these errors on the server and find out if the deviceType was sent?

@gholias
Copy link

gholias commented Jan 24, 2016

Im also having this problem. Any workaround?

@grantland
Copy link
Contributor

@alexblack that is possible, but you'd have to go through the backend support for backend issues as we only support SDK issues on this repository: http://parse.com/help > contact us > REST API

@alexblack
Copy link
Author

Hmm, as far as I can tell this is an issue with the SDK since it started with the SDK change from 1.9.1 to 1.9.2.

@hatpick
Copy link

hatpick commented Sep 9, 2016

What's the progress on this? I'm still getting it on 1.13.1

@petritz
Copy link

petritz commented Sep 17, 2016

I have the same problem! Is there a workaround? I need this ASAP

@kcoder666
Copy link

We're encountering this issue massively on 1.13.2 after switching from parse.com to our own Parse server. Thousands of Android users are affected every day. Some are extremely frustrated because they have tried to log in hundred of times without success. Even factory reset does not work (from the user feedback as we also could not reproduce this).
Perhaps this issue is from the Android SDK because our iOS users are not affected. So any progress on this?

@kunalseedoc
Copy link

facing this issue for thousands of users can anybody suggest a workaround?

@alexblack
Copy link
Author

We saw this ages ago when updating to version 1.9.2, there was no real solution to it, getting our users to reinstall our app was a workaround.

Recently we migrated from parse.com to parse-server, and didn't encounter this as a problem.

@yaaminu
Copy link

yaaminu commented Nov 12, 2016

I've been facing similar issues in my app and I have almost no clue how to go about it. Any quick fix?

@kry55
Copy link

kry55 commented Jul 24, 2018

There is a workaround (I had that problem in 1.17.3), just add:

installation.put("deviceType", "android");

before you call save. Unfortunately "deviceType" field is read only so you need to alter ParseInstallation.java file and compile SDK:

  private static final List<String> READ_ONLY_FIELDS = Collections.unmodifiableList(
      Arrays.asList(/*KEY_DEVICE_TYPE, */KEY_INSTALLATION_ID, KEY_DEVICE_TOKEN, KEY_PUSH_TYPE,
          KEY_TIME_ZONE, KEY_LOCALE, KEY_APP_VERSION, KEY_APP_NAME, KEY_PARSE_VERSION,
          KEY_APP_IDENTIFIER, KEY_OBJECT_ID));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:bug Impaired feature or lacking behavior that is likely assumed
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants