Skip to content

ParseUser$State java.lang.ClassCastException: org.json.JSONObject$1 cannot be cast to java.lang.String #209

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

Closed
vfede opened this issue Oct 21, 2015 · 63 comments

Comments

@vfede
Copy link

vfede commented Oct 21, 2015

I updated sdk from 1.10.0 to 1.10.3, now on ParseUser.logOut() I have this error apparently at random.
happened on my development app as well as production app.
Everything was working fine before the upgrade.
if need anything more I will try to be helpful.

this is part of MyUser class

@ParseClassName("_User")
public class MyUser extends ParseUser {

//more methods

public synchronized String getUserId() {
        if (getObjectId() == null)
        try {
            save();
            } catch(ParseException e) {
            String tempUserId = preferences.getString("temp-user-id", "");
                if (tempUserId.isEmpty()) {
                    tempUserId = ("unknown-user" + randomNumber);
                    preferencesEditor.putString("temp-user-id", tempUserId).commit();
                }
                return tempUserId;
            }

        return getObjectId();
    }

public static MyUser getCurrentUser() {
        return (MyUser) ParseUser.getCurrentUser();
    }


public static void logOut() {
        unsubscribeToPush(getCurrentUser().getUserId());
        ParseUser.logOut();   //line 211
        getCurrentUser().setAppVersion();
        subscribeToPush(getCurrentUser().getUserId());
    }

private static void unsubscribeToPush(String userId) {
        ParsePush.unsubscribeInBackground("user_" + userId);
    }
}
com.mypackage E/AndroidRuntime: FATAL EXCEPTION: main
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime: java.lang.ClassCastException: org.json.JSONObject$1 cannot be cast to java.lang.String
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at com.parse.ParseUser$State.sessionToken(ParseUser.java:134)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at com.parse.ParseUser.logOutAsync(ParseUser.java:1000)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at com.parse.ParseUser.logOutAsync(ParseUser.java:991)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at com.parse.CachedCurrentUserController$4$1$1.then(CachedCurrentUserController.java:186)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at com.parse.CachedCurrentUserController$4$1$1.then(CachedCurrentUserController.java:179)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at bolts.Task$15.run(Task.java:825)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at bolts.BoltsExecutors$ImmediateExecutor.execute(BoltsExecutors.java:105)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at bolts.Task.completeAfterTask(Task.java:816)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at bolts.Task.continueWithTask(Task.java:628)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at bolts.Task.continueWithTask(Task.java:639)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at bolts.Task$13.then(Task.java:731)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at bolts.Task$13.then(Task.java:719)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at bolts.Task$15.run(Task.java:825)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at bolts.BoltsExecutors$ImmediateExecutor.execute(BoltsExecutors.java:105)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at bolts.Task.completeAfterTask(Task.java:816)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at bolts.Task.continueWithTask(Task.java:628)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at bolts.Task.continueWithTask(Task.java:603)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at bolts.Task.onSuccessTask(Task.java:719)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at bolts.Task.onSuccessTask(Task.java:709)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at bolts.Task.onSuccessTask(Task.java:743)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at com.parse.CachedCurrentUserController$4$1.then(CachedCurrentUserController.java:179)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at com.parse.CachedCurrentUserController$4$1.then(CachedCurrentUserController.java:176)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at bolts.Task$15.run(Task.java:825)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at bolts.BoltsExecutors$ImmediateExecutor.execute(BoltsExecutors.java:105)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at bolts.Task.completeAfterTask(Task.java:816)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at bolts.Task.continueWithTask(Task.java:628)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at bolts.Task.continueWithTask(Task.java:639)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at com.parse.CachedCurrentUserController$4.then(CachedCurrentUserController.java:176)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at com.parse.CachedCurrentUserController$4.then(CachedCurrentUserController.java:170)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at com.parse.TaskQueue.enqueue(TaskQueue.java:69)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at com.parse.CachedCurrentUserController.logOutAsync(CachedCurrentUserController.java:170)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at com.parse.ParseUser.logOutInBackground(ParseUser.java:955)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at com.parse.ParseUser.logOut(ParseUser.java:982)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at com.mypackage.nova_framework.user.MyUser.logOut(MyUser.java:211)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at com.mypackage.info_page.InfoPageActivity$5.onClick(InfoPageActivity.java:311)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java:166)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at android.os.Handler.dispatchMessage(Handler.java:99)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at android.os.Looper.loop(Looper.java:137)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at android.app.ActivityThread.main(ActivityThread.java:4441)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at java.lang.reflect.Method.invokeNative(Native Method)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Method.java:511)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:565)
10-21 16:33:55.585 3764-3764/com.mypackage E/AndroidRuntime:     at dalvik.system.NativeStart.main(Native Method)
@parse-github-bot
Copy link

Thank you for your feedback. We prioritize issues that have clear and concise repro steps. Please see our Bug Reporting Guidelines about what information should be added to this issue.

Please try the latest SDK. Our release notes have details about what issues were fixed in each release.

In addition, you might find the following resources helpful:

@grantland
Copy link
Contributor

It's not obvious to me how this could be happening. Would you be able to provide a small project that reproduces this issue and possibly attach a debugger and tell me the information that's in ParseUser.State.serverData? Feel free to remove any private data.

@vfede
Copy link
Author

vfede commented Oct 22, 2015

ok, I will schedule this and reply asap.

@parse-github-bot
Copy link

This issue has not been updated for 7 days. If you have additional information to help pinpoint this issue as an SDK bug, please comment on this issue. We will close this issue in 7 days if no additional information is provided. Thank you for your feedback.

@alexblack
Copy link

Some of my users have seen this too since upgrading to 1.10.3

http://crashes.to/s/18e58f0f97a

Non-fatal Exception: java.lang.ClassCastException: org.json.JSONObject$1 cannot be cast to java.lang.String
       at com.parse.ParseUser$8$1.i(ProGuard)
       at com.parse.NetworkUserController.logInAsync(ProGuard)
       at com.parse.ParseURLConnectionHttpClient.b(ProGuard)
       at com.parse.ParseURLConnectionHttpClient.socketOperationTimeout(ProGuard)
       at bolts.Task$15.run(ProGuard)
       at bolts.BoltsExecutors$ImmediateExecutor.execute(ProGuard)
       at bolts.Task.completeAfterTask(ProGuard)
       at bolts.Task.continueWithTask(ProGuard)
       at bolts.Task.continueWithTask(ProGuard)
       at bolts.Task$13.then(ProGuard)
       at bolts.Task$13.then(ProGuard)
       at bolts.Task$15.run(ProGuard)
       at bolts.BoltsExecutors$ImmediateExecutor.execute(ProGuard)
       at bolts.Task.completeAfterTask(ProGuard)
       at bolts.Task.continueWithTask(ProGuard)
       at bolts.Task.continueWithTask(ProGuard)
       at bolts.Task.onSuccessTask(ProGuard)
       at bolts.Task.onSuccessTask(ProGuard)
       at bolts.Task.onSuccessTask(ProGuard)
       at com.parse.ParseTaskUtils$2$1.this$0(ProGuard)
       at com.parse.ParseTaskUtils$2$1.val$task(ProGuard)
       at com.parse.ParseTaskUtils$2$1.this$0(ProGuard)
       at com.parse.ParseObject$10$1.val$user(ProGuard)
       at com.parse.ParseObject$10$1.val$acl(ProGuard)
       at com.parse.PushService$1.$SwitchMap$com$parse$PushType(ProGuard)
       at com.parse.ParseNotificationManager$Singleton.g(ProGuard)
       at com.parse.ParseObject$8.b(ProGuard)
       at com.parse.ParseObject$8.this$0(ProGuard)
       at bolts.Task$15.run(ProGuard)
       at bolts.BoltsExecutors$ImmediateExecutor.execute(ProGuard)
       at bolts.Task.completeAfterTask(ProGuard)
       at bolts.Task.continueWithTask(ProGuard)
       at bolts.Task.continueWithTask(ProGuard)
       at bolts.Task$13.then(ProGuard)
       at bolts.Task$13.then(ProGuard)
       at bolts.Task$15.run(ProGuard)
       at bolts.BoltsExecutors$ImmediateExecutor.execute(ProGuard)
       at bolts.Task.completeAfterTask(ProGuard)
       at bolts.Task.continueWithTask(ProGuard)
       at bolts.Task.continueWithTask(ProGuard)
       at bolts.Task.onSuccessTask(ProGuard)
       at bolts.Task.onSuccessTask(ProGuard)
       at bolts.Task.onSuccessTask(ProGuard)
       at com.parse.ParseNotificationManager$Singleton.N(ProGuard)
       at com.aadhk.woinvoice.util.ParseInit.initParseUser(ProGuard)
       at com.aadhk.woinvoice.App$5.run(ProGuard)
       at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java)
       at java.util.concurrent.FutureTask.run(FutureTask.java)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java)
       at java.lang.Thread.run(Thread.java)

Here is a snippet with line numbers:

com.parse.ParseUser$8$1.i (ProGuard:134)
com.parse.NetworkUserController.logInAsync (ProGuard:80)
com.parse.ParseURLConnectionHttpClient.b (ProGuard:1380)
com.parse.ParseURLConnectionHttpClient.socketOperationTimeout (ProGuard:1377)
bolts.Task$15.run (ProGuard:825)
bolts.BoltsExecutors$ImmediateExecutor.execute (ProGuard:105)
bolts.Task.completeAfterTask (ProGuard:816)
bolts.Task.continueWithTask (ProGuard:628)
bolts.Task.continueWithTask (ProGuard:639)

This is happening in when my code is saving the ParseUser:

public Task<ParseUser> initParseUser() {
    Log.d(TAG, "initParseUser");
    final TimingLogger timings = new TimingLogger(TAG, "initParseUser");
    ParseUser.enableAutomaticUser();
    timings.addSplit("enableAutomaticUser");

    final ParseUser user = ParseUser.getCurrentUser();
    user.put("accountId", accountId);
    try {
      user.put("countryCode", AccountUtil.getCountryCode(ctx));
    } catch (Exception e) {
      App.err(ctx, "Failed to put properties onto ParseUser", e);
    }

    return user.saveInBackground().continueWithTask(new Continuation<Void, Task<ParseUser>>() {
      @Override
      public Task<ParseUser> then(Task<Void> task) throws Exception {
        timings.addSplit("saveUser");
        if (task.isFaulted()) {
          logParseUserException(task.getError());
          return Task.forError(task.getError());
        } else {
          Log.d(TAG, "Successfully initialized parseUser: " + user.getObjectId());
          return Task.forResult(user);
        }
      }
    });
  }

  private void logParseUserException(Exception e) {
    if (e instanceof  ParseException) {
      final ParseException pe = (ParseException) e;
      switch (pe.getCode()) {
        case ParseException.CONNECTION_FAILED:
          // do nothing
          break;
        default:
          // wrap it to gve us context
          App.err(ctx, "Failed to save parse user: " + pe.getCode(), new Exception(e));
          break;
      }
    } else {
      App.err(ctx, "Failed to save parse user", e);
    }
  }

@alexblack
Copy link

I found 3 users this happened for. The sequence of events was like this:

  1. They install the app
  2. The app logs an error that it can't save the ParseInstallation
  3. Neither the ParseUser nor ParseInstallation appear to get saved (my app logs the objectId for each of these, and all 3 users are missing these values)
  4. Later the app logs an error that the ParseUser cannot be saved (JSONObject$ error above)

This is odd because my code will not save the ParseInstallation until the ParseUser is saved. Its also odd that the ParseInstallation error comes first.

It looks to me like the ParseUser fails to save, but, saveInBackground completes successfully, letting my code move ahead to try to save the ParseInstallation, which then fails to save because I reference the ParseUser on it.

Perhaps on a subsequent app launch the app tries to save the ParseUser again, and this time an error is thrown.

Here is the ParseInstallation error:

Failed to save parse installation 
ex  java.lang.IllegalStateException: unable to encode an association with an unsaved ParseObject 
stacktrace  java.lang.Exception: java.lang.IllegalStateException: unable to encode an association with an unsaved ParseObject at com.aadhk.woinvoice.util.eh.b(ProGuard:165) at com.aadhk.woinvoice.util.eh.a(ProGuard:156) at a.u.run(ProGuard:825) at a.h.execute(ProGuard:105) at a.n.d(ProGuard:816) at a.n.b(ProGuard:32) at a.q.b(ProGuard:621) at a.q.a(ProGuard:618) at a.n.k(ProGuard:861) at a.n.c(ProGuard:32) at a.ab.a(ProGuard:932) at a.ab.b(ProGuard:959) at a.v.b(ProGuard:840) at a.v.a(ProGuard:829) at a.t.run(ProGuard:784) at a.h.execute(ProGuard:105) at a.n.c(ProGuard:775) at a.n.a(ProGuard:32) at a.p.b(ProGuard:567) at a.p.a(ProGuard:564) at a.n.k(ProGuard:861) at a.n.c(ProGuard:32) at a.ab.a(ProGuard:932) at a.ab.b(ProGuard:959) at a.v.b(ProGuard:840) at a.v.a(ProGuard:829) at a.t.run(ProGuard:784) at a.h.execute(ProGuard:105) at a.n.c(ProGuard:775) at a.n.a(ProGuard:32) at a.p.b(ProGuard:567) at a.p.a(ProGuard:564) at a.n.k(ProGuard:861) at a.n.c(ProGuard:32) at a.ab.a(ProGuard:932) at a.ab.b(ProGuard:959) at a.v.b(ProGuard:840) at a.v.a(ProGuard:829) at a.t.run(ProGuard:784) at a.h.execute(ProGuard:105) at a.n.c(ProGuard:775) at a.n.a(ProGuard:574) at a.n.a(ProGuard:585) at a.u.run(ProGuard:829) at a.h.execute(ProGuard:105) at a.n.d(ProGuard:816) at a.n.b(ProGuard:32) at a.q.b(ProGuard:621) at a.q.a(ProGuard:618) at a.n.k(ProGuard:861) at a.n.c(ProGuard:32) at a.ab.a(ProGuard:932) at a.ab.b(ProGuard:959) at a.v.b(ProGuard:840) at a.v.a(ProGuard:829) at a.t.run(ProGuard:784) at a.h.execute(ProGuard:105) at a.n.c(ProGuard:775) at a.n.a(ProGuard:574) at a.n.a(ProGuard:585) at a.u.run(ProGuard:829) at a.h.execute(ProGuard:105) at a.n.d(ProGuard:816) at a.n.b(ProGuard:32) at a.q.b(ProGuard:621) at a.q.a(ProGuard:618) at a.n.k(ProGuard:861) at a.n.c(ProGuard:32) at a.ab.a(ProGuard:916) at a.ab.b(ProGuard:950) at a.v.b(ProGuard:842) at a.v.a(ProGuard:829) at a.t.run(ProGuard:784) at a.h.execute(ProGuard:105) at a.n.c(ProGuard:775) at a.n.a(ProGuard:574) at a.n.a(ProGuard:585) at a.u.run(ProGuard:829) at a.h.execute(ProGuard:105) at a.n.d(ProGuard:816) at a.n.b(ProGuard:32) at a.q.b(ProGuard:621) at a.q.a(ProGuard:618) at a.n.k(ProGuard:861) at a.n.c(ProGuard:32) at a.ab.a(ProGuard:916) at a.ab.b(ProGuard:950) at a.z.b(ProGuard:477) at a.z.a(ProGuard:451) at a.t.run(ProGuard:784) 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: java.lang.IllegalStateException: unable to encode an association with an unsaved ParseObject at com.parse.rv.a(ProGuard:31) at com.parse.io.b(ProGuard:42) at com.parse.qq.b(ProGuard:27) at com.parse.io.b(ProGuard:129) at com.parse.mi.a(ProGuard:60) at com.parse.bj.a(ProGuard:61) at com.parse.kr.b(ProGuard:1640) at com.parse.kr.a(ProGuard:1635) 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) at a.u.run(ProGuard:825) ... 32 more  
errid   c22143ec-05f4-4034-bc10-7856e4a89e01 
name    error 
appversion  0.1.171 

My code:

  private void initParse(final Task<ParseUser>.TaskCompletionSource onParseUser) {
    final ParseInit parseInit = new ParseInit(getApplicationContext(), accountId);
    // Unfortunately have to do this part on the UI thread
    parseInit.init();

    executor.submit(new Runnable() {
      @Override
      public void run() {
        // Initialize the parse user
        parseInit.initParseUser().onSuccessTask(new Continuation<ParseUser, Task<ParseInstallation>>() {
          @Override
          public Task<ParseInstallation> then(Task<ParseUser> task) throws Exception {
            final ParseUser parseUser = task.getResult();
            setVisitorProperty("parseUser", parseUser.getObjectId());
            onParseUser.setResult(parseUser);

            // Initialize the parse installation
            return parseInit.initParseInstallation().continueWithTask(new Continuation<ParseInstallation, Task<ParseInstallation>>() {
              @Override
              public Task<ParseInstallation> then(Task<ParseInstallation> task) throws Exception {
                if (task.isFaulted()) {
                  // Retry once, try to work around bug that causes '135 deviceType not specified' errors
                  // https://github.com/ParsePlatform/Parse-SDK-Android/issues/203#issuecomment-150045761
                  return parseInit.initParseInstallation().onSuccess(new Continuation<ParseInstallation, ParseInstallation>() {
                    @Override
                    public ParseInstallation then(Task<ParseInstallation> task) throws Exception {
                      App.logEvent(App.this, "parse-installation", "retry-success", task.getResult().getObjectId());
                      return task.getResult();
                    }
                  }, executor);
                } else {
                  return task;
                }
              }
            }, executor);
          }
        }, executor).onSuccess(new Continuation<ParseInstallation, Void>() {
          @Override
          public Void then(Task<ParseInstallation> task) throws Exception {
            final ParseInstallation parseInstallation = task.getResult();
            setVisitorProperty("parseInstall", parseInstallation.getObjectId());
            onParseInstallation(task.getResult());
            return null;
          }
        }, executor);
      }
    });
  }

/**
 * Helper to manage initializing parse
 */
public class ParseInit {
  private static final String TAG = "ParseInit";

  private final Context ctx;
  private final String accountId;

  public ParseInit(Context ctx, String accountId) { this.ctx = ctx; this.accountId = accountId; }

  /**
   * Must be called on the UI thread, otherwise app can crash on close
   */
  public void init() {
    Log.d(TAG, "init");
    final TimingLogger timings = new TimingLogger(TAG, "init");

    try {
      final boolean debug = isDebug(ctx);
      final String appId = debug ? Constant.PARSE_DEV_APP_ID : Constant.PARSE_APP_ID;
      final String clientKey = debug ? Constant.PARSE_DEV_CLIENT_KEY : Constant.PARSE_CLIENT_KEY;
      Log.d(TAG, String.format("initParse (AppId=%s, ClientKey=%s)", appId, clientKey));

      ParseObject.registerSubclass(ParseClient.class);
      ParseObject.registerSubclass(ParseItem.class);
      ParseObject.registerSubclass(ParseInvoice.class);
      ParseObject.registerSubclass(ParseAccount.class);
      ParseObject.registerSubclass(ParseGoogleAccount.class);
      ParseObject.registerSubclass(ParseMsg.class);
      ParseObject.registerSubclass(ParseSubscription.class);
      ParseObject.registerSubclass(ParseFunnel.class);
      ParseObject.registerSubclass(ParsePhoto.class);

      timings.addSplit("register");
      Parse.enableLocalDatastore(ctx);
      timings.addSplit("datastore");
      Parse.initialize(ctx, appId, clientKey);
      timings.addSplit("initialize");
    } catch (Exception e) {
      App.err(ctx, "Failed to init parse", e);
    }

    timings.dumpToLog();
  }

  public Task<ParseUser> initParseUser() {
    Log.d(TAG, "initParseUser");
    final TimingLogger timings = new TimingLogger(TAG, "initParseUser");
    ParseUser.enableAutomaticUser();
    timings.addSplit("enableAutomaticUser");

    final ParseUser user = ParseUser.getCurrentUser();
    user.put("accountId", accountId);
    try {
      user.put("countryCode", AccountUtil.getCountryCode(ctx));
    } catch (Exception e) {
      App.err(ctx, "Failed to put properties onto ParseUser", e);
    }

    return user.saveInBackground().continueWithTask(new Continuation<Void, Task<ParseUser>>() {
      @Override
      public Task<ParseUser> then(Task<Void> task) throws Exception {
        timings.addSplit("saveUser");
        if (task.isFaulted()) {
          logParseUserException(task.getError());
          return Task.forError(task.getError());
        } else {
          Log.d(TAG, "Successfully initialized parseUser: " + user.getObjectId());
          return Task.forResult(user);
        }
      }
    });
  }

  private void logParseUserException(Exception e) {
    if (e instanceof ParseException) {
      final ParseException pe = (ParseException) e;
      switch (pe.getCode()) {
        case ParseException.CONNECTION_FAILED:
          // do nothing
          break;
        default:
          // wrap it to gve us context
          App.err(ctx, "Failed to save parse user: " + pe.getCode(), new Exception(e));
          break;
      }
    } else {
      App.err(ctx, "Failed to save parse user", e);
    }
  }

  private static boolean isDebug(Context ctx) {
    // http://stackoverflow.com/questions/2718565/best-way-to-include-debug-code
    int appFlags = ctx.getApplicationInfo().flags;
    return (appFlags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
  }

  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

Are either of you happening to be using lazy users and cloud code such as before/afterSave for your _User objects?

Also once either of you are able to reproduce this, it'd be great to get repro steps/project as well as the User object stored in sqlite/disk and the network information from our logging tools (feel free to remove any private information). I mainly need what's getting passed around in the sessionToken key.

@alexblack
Copy link

Whats a lazy user? I'm not using before/afterSave on my users. I think I've shared all my user code above.

I find it really hard to reproduce these parse bugs. sorry man.

@grantland
Copy link
Contributor

Lazy users are also known as anonymous or automatic users: https://parse.com/docs/android/guide#users-anonymous-users

It's all good, these edge case issues are always harder to track down, but luckily that also means that they don't happen often for users either.

@alexblack
Copy link

Gotcha. Yes my code uses anonymous users, this can be seen in the code I pasted above.

ParseUser.enableAutomaticUser();

@grantland
Copy link
Contributor

Sorry, I totally missed that 😞

@alexblack
Copy link

Np, I pasted a lot of code, thx for your help with this and other issues!

@vfede
Copy link
Author

vfede commented Nov 5, 2015

I use lazy users, I'm not using before/afterSave on my users.
The order of my initialization is like this:
(and it did not change between my app versions, the only thing I changed was parse sdk from 1.10.0. to .3, could be an issue that's happening once on upgrading?)

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        Parse.enableLocalDatastore(this);
        ParseObject.registerSubclass(MyUser.class);
        Parse.initialize(...);
        ParseFacebookUtils.initialize(appContext, REQUESTCODE_FACEBOOK);
        FacebookSdk.sdkInitialize(appContext);
        MyUser.enableAutomaticUser();
        String userId = MyUser.getUserId(); //does the first user save, see first post
        ...

is there any problem? I noticed that in the Parse tutorials you enable the localDatastore after the registering of User subclass. Can this be a problem because of the "single instance" the localDatastore introduces? The documentation does not talk about the relative execution order of these methods.

@vfede
Copy link
Author

vfede commented Nov 5, 2015

the same exception is happening in the first save() in my getUserId method (first post updated with code)

http://crashes.to/s/a157a3adf63

@vfede
Copy link
Author

vfede commented Nov 9, 2015

can this be related? #138

@grantland
Copy link
Contributor

You're onCreate() looks fine, execution order of those methods shouldn't matter and I'm unsure whether #138 is related until we get a repro from the developer.

Are either of you able to reproduce successfully? From the information you've both provided, we would need the network requests being sent/received or the on disk user data to further debug this issue.

@alexblack
Copy link

I haven't tried to repro, I'm not sure what would cause this bug. Can you offer any insight as to what might be required to repro? I've never seen these methods fail for me in this manner.

@grantland
Copy link
Contributor

Unfortunately this seems like an impossible scenario for me, so I'm not entirely sure how this could happen or even reproduce it.

From my current understanding of the problem, somehow a JSONObject is getting into the ParseUser's sessionToken key, which is why I'm trying to discern whether the server is returning invalid responses or something is broken in the SDK.

@alexblack
Copy link

@grantland what code would you like me to add to my app to capture/log data to help get this bug fixed?

@alexblack
Copy link

Bump

@parse-github-bot
Copy link

This issue has not been updated for 7 days. If you have additional information to help pinpoint this issue as an SDK bug, please comment on this issue. We will close this issue in 7 days if no additional information is provided. Thank you for your feedback.

@alexblack
Copy link

I don't have any additional info, I'm waiting for response

@parse-github-bot
Copy link

This issue has not been updated for 7 days. If you have additional information to help pinpoint this issue as an SDK bug, please comment on this issue. We will close this issue in 7 days if no additional information is provided. Thank you for your feedback.

@alexblack
Copy link

@grantland any further data you need from me to help figure this one out?

@grantland
Copy link
Contributor

Unfortunately we won't be able to investigate this further without the user JSON that was sent over the network and the same JSON persisted in LDS which requires you to be able to reproduce this issue on a development device.

@alexblack
Copy link

What is LDS? So is there no way for me to add code to get that data? Could you add code to the SDK to expose it?

If you have some suggestions on how to repro I'd be happy to try them out.

The JSON sent over the network - that comes from you guys, right? I'm not sure I can help you there.

@grantland
Copy link
Contributor

LDS is Local Datastore

LDS is not accessible programmatically and there aren't plans to enable access to it programmatically due to the fact that the internal storage mechanism and format is subject to change.

Gathering data sent over the network on our side isn't a viable option since we won't be able to isolate requests that cause issues in live clients.

With these two limitations, the only way to proceed with this issue is for this to be reproduced on a development device so that we can use tools like ParseInterceptors and adb to monitor the network requests and SQLite storage on the device.

@alexblack
Copy link

Hey @grantland lets focus on things we can do, not things we can't :) If you are able to repro this locally, then great, but I have no idea where to start on this to cause this parse bug to repro.

I do have users who experience this bug, and I'm happy to add any code necessary. I'd imagine if we both were willing to add some code to track this down then it could be solved. It sounds like you're saying you're not willing to take the steps necessary to solve this.

Thinking aloud, couldn't I also just write some code to grab your LDS sqlite database and upload it when this issue happens?

If this bug was in my code, here are things I would do:

  • Add more logging/details when the bug occurs, eg log it to my backend, include more details in the exception
  • Make the code more defensive, possibly implement a workaround blindly, based on what we know so far

@grantland
Copy link
Contributor

Debugging an issue in the wild is not something I'd recommend, but if you're willing to dive into unsupported territory, you can find our SQLite storage configurations here: https://github.com/ParsePlatform/Parse-SDK-Android/blob/master/Parse/src/main/java/com/parse/OfflineSQLiteOpenHelper.java#L60

I understand that this might be an error within our SDK, but without concise repro steps we don't have enough information to pinpoint the problem to solve it and therefore do not have any actionable items without it. Please see our Contributing Guidelines for more information regarding bug reporting.

@parse-github-bot
Copy link

This issue has not been updated for 7 days. If you have additional information to help pinpoint this issue as an SDK bug, please comment on this issue. We will close this issue in 7 days if no additional information is provided. Thank you for your feedback.

4 similar comments
@parse-github-bot
Copy link

This issue has not been updated for 7 days. If you have additional information to help pinpoint this issue as an SDK bug, please comment on this issue. We will close this issue in 7 days if no additional information is provided. Thank you for your feedback.

@parse-github-bot
Copy link

This issue has not been updated for 7 days. If you have additional information to help pinpoint this issue as an SDK bug, please comment on this issue. We will close this issue in 7 days if no additional information is provided. Thank you for your feedback.

@parse-github-bot
Copy link

This issue has not been updated for 7 days. If you have additional information to help pinpoint this issue as an SDK bug, please comment on this issue. We will close this issue in 7 days if no additional information is provided. Thank you for your feedback.

@parse-github-bot
Copy link

This issue has not been updated for 7 days. If you have additional information to help pinpoint this issue as an SDK bug, please comment on this issue. We will close this issue in 7 days if no additional information is provided. Thank you for your feedback.

@dazza5000
Copy link

I'm experiencing this issue. Did anyone find a fix for it?

@lolobosse
Copy link

+1 Same issue with this code:

ParseUser.getCurrentUser().saveEventually

And the trace is this one:

Stack Trace
_________________________________
0   java.lang.ClassCastException: org.json.JSONObject$1 cannot be cast to java.lang.String
1       at com.parse.ParseUser$State.sessionToken(ParseUser.java:134)
2       at com.parse.ParseUser.getSessionToken(ParseUser.java:308)
3       at com.parse.ParseUser.getCurrentSessionToken(ParseUser.java:916)
4       at com.parse.ParseObject.saveEventually(ParseObject.java:1606)
5       at com.parse.ParseObject.saveEventually(ParseObject.java:1553)
6       at jobninja.eu.jobninja.activities.newResumeActivity.NewResumeActivity$2.onClick(NewResumeActivity.java:156)
7       at android.view.View.performClick(View.java:4640)
8       at android.view.View$PerformClick.run(View.java:19421)
9       at android.os.Handler.handleCallback(Handler.java:733)
10      at android.os.Handler.dispatchMessage(Handler.java:95)
11      at android.os.Looper.loop(Looper.java:136)
12      at android.app.ActivityThread.main(ActivityThread.java:5476)
13      at java.lang.reflect.Method.invokeNative(Native Method)
14      at java.lang.reflect.Method.invoke(Method.java:515)
15      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
16      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
17      at dalvik.system.NativeStart.main(Native Method)

I use the latest version (1.13.0)

@mediaexpander
Copy link

mediaexpander commented May 16, 2016

FIXED The exception was thrown when the User had issues disconnecting. Nothing to do with Android API or device.

Hi,

I am having this same issue with this code on an Android Api 17 (Samsung Galaxy Trend Plus)

ParseQuery query = ParseQuery.getQuery("MyClass");
query.whereEqualTo("aKey",aValue);
query.findInBackground(new FindCallback() {
@OverRide
public void done(List objects, ParseException e) {

            if (e!=null){
                e.printStackTrace();


            }
     });

Does anyone know how to solve it? This exact code is working on other devices. It's really weird.

Thank you

@yshrsmz
Copy link

yshrsmz commented Aug 23, 2016

@grantland I got serverData dump.

I got following log via crashlytics, with parseUser.getState().toString()

com.parse.ParseUser$State@41eedbb0[className=_User, objectId=OBJECT_ID_STRING, createdAt=1471913285735, updatedAt=1471913286333, isComplete=true, serverData={sessionToken=null, username=USER_NAME_STRING, authData={}}]

apparently, sessionToken is null :(
but not sure why this will cause ClassCastException.
(I replaced objectId and username, but it's ordinary objectId & username)

@yshrsmz
Copy link

yshrsmz commented Aug 23, 2016

maybe a stored value in sessionToken is JSONObject.NULL ?

@asielgil88
Copy link

I got same issue on user fetch any solution ?

@yshrsmz
Copy link

yshrsmz commented Dec 25, 2016

@asielgil88

current workaround which is working for me is this:

package com.parse;

import org.json.JSONObject;

public class ParseUtil {

    private ParseUtil() {
        // no-op
    }

    public static String getCurrentSessionToken() {
        return getSessionToken(ParseUser.getCurrentUser());
    }

    public static String getSessionToken(ParseUser parseUser) {
        if (parseUser == null) {
            return null;
        }

        Object value = parseUser.getState().get("sessionToken");
        if (JSONObject.NULL.equals(value)) {
            return null;
        }

        return (String) value;
    }
}

@frangulyan
Copy link

I have the same issue - session token null for anonymous user after calling saveInBackground(). For some reason calling enableLocalDataStore() in the beginning (and reinstalling the app) fixes it...

@lxknvlk
Copy link

lxknvlk commented Aug 16, 2017

This still happens. When i update an app, the crash in parse sdk happens here:
ParseUser.java:
public String sessionToken() {
return (String) get(KEY_SESSION_TOKEN); //here the class cast exception is thrown
}

i believe it is because the session token itself is null.

The other question, is why the session token becomes null?

jhansche added a commit to wondrous-io/Parse-SDK-Android that referenced this issue Aug 24, 2017
jhansche added a commit to wondrous-io/Parse-SDK-Android that referenced this issue Aug 24, 2017
jhansche added a commit to wondrous-io/Parse-SDK-Android that referenced this issue Aug 24, 2017
@jhansche
Copy link
Contributor

PR to fix the cast issue: #723

@natario1
Copy link
Contributor

natario1 commented Sep 1, 2017

This should be fixed by #724 , if you still see some of these, please let us know

@natario1 natario1 closed this as completed Sep 1, 2017
@flovilmart flovilmart reopened this Jan 16, 2018
jhansche added a commit to wondrous-io/Parse-SDK-Android that referenced this issue Jan 19, 2018
mmimeault added a commit that referenced this issue Jan 22, 2018
Check for JSONObject.NULL before casting to String [Fixes #209]
bitterbit pushed a commit to bitterbit/Parse-SDK-Android that referenced this issue Mar 9, 2018
Check for JSONObject.NULL before casting to String [Fixes parse-community#209]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests