Meteor.user() Returns undefined after updating to 1.12

After updating a project from 1.11 to 1.12 I am getting undefined when using Meteor.user(). I thought it may have been an issue with it not existing yet but even when attempting to console log while logged in from a button click it is always undefined. I am able to log in using Meteor.loginWithPassword, and Meteor.userId() returns the id just fine. Has anyone else run into this, or know what could be causing it?

I have verified that the issue only occurs after running meteor upate on the project.

Packages

meteor-base@1.4.0 # Packages every Meteor app needs to have
mobile-experience@1.1.0 # Packages for a great mobile UX
mongo@1.10.1 # The database Meteor supports right now
reactive-var@1.0.11 # Reactive variable for tracker
tracker@1.2.0 # Meteor’s client-side reactive programming library
standard-minifier-css@1.7.1 # CSS minifier run for production mode
standard-minifier-js@2.6.0 # JS minifier run for production mode
shell-server@0.5.0 # Server-side component of the meteor shell command
session@1.2.0
underscore@1.0.10
akryum:vue-component
accounts-password@1.6.2
http@1.4.2
littledata:synced-cron
ardatan:webpack
ardatan:webpack-dev-middleware
momentjs:moment

Versions

accounts-base@1.7.1
accounts-password@1.6.3
akryum:vue-component@0.15.2
akryum:vue-component-dev-client@0.4.7
akryum:vue-component-dev-server@0.1.4
allow-deny@1.1.0
ardatan:webpack@0.0.13
ardatan:webpack-dev-middleware@0.0.13
autoupdate@1.6.0
babel-compiler@7.5.4
babel-runtime@1.5.0
base64@1.0.12
binary-heap@1.0.11
boilerplate-generator@1.7.1
caching-compiler@1.2.2
callback-hook@1.3.0
check@1.3.1
ddp@1.4.0
ddp-client@2.3.3
ddp-common@1.4.0
ddp-rate-limiter@1.0.9
ddp-server@2.3.2
diff-sequence@1.1.1
dynamic-import@0.5.4
ecmascript@0.14.4
ecmascript-runtime@0.7.0
ecmascript-runtime-client@0.11.0
ecmascript-runtime-server@0.10.0
ejson@1.1.1
email@2.0.0
es5-shim@4.8.0
fetch@0.1.1
geojson-utils@1.0.10
hot-code-push@1.0.4
http@1.4.2
id-map@1.1.0
inter-process-messaging@0.1.1
launch-screen@1.2.0
littledata:synced-cron@1.5.1
livedata@1.0.18
localstorage@1.2.0
logging@1.1.20
meteor@1.9.3
meteor-base@1.4.0
minifier-css@1.5.3
minifier-js@2.6.0
minimongo@1.6.1
mobile-experience@1.1.0
mobile-status-bar@1.1.0
modern-browsers@0.1.5
modules@0.15.0
modules-runtime@0.12.0
momentjs:moment@2.29.1
mongo@1.10.1
mongo-decimal@0.1.2
mongo-dev-server@1.1.0
mongo-id@1.0.7
npm-bcrypt@0.9.3
npm-mongo@3.8.1
ordered-dict@1.1.0
promise@0.11.2
random@1.2.0
rate-limit@1.0.9
reactive-dict@1.3.0
reactive-var@1.0.11
reload@1.3.1
retry@1.1.0
routepolicy@1.1.0
service-configuration@1.0.11
session@1.2.0
sha@1.0.9
shell-server@0.5.0
socket-stream-client@0.3.1
srp@1.1.0
standard-minifier-css@1.7.1
standard-minifier-js@2.6.0
tracker@1.2.0
underscore@1.0.10
url@1.3.1
webapp@1.9.1
webapp-hashing@1.0.9

An undefined value has always been there during initial loading (same for userId()) - does it eventually switch over to an object or null?

For userId() it works like this:

undefined - initializing
null - not logged in
idXXXXXXX - logged in

Edit: ER, you covered that - should have read the whole post before commenting!

If I remember this correctly, Meteor will set the userId first and then send the user data as publication. So userId will be sent first and then user data. Better to check loggingIn

Meteor.user() only started being undefined throughout the project after updating. I tested on multiple projects. While on 1.11 everything is fine. After running meteor update, boom undefined. I am aware that it is undefined for a small amount of time during loading, but here it is staying undefined.

What do you mean by checking logging in? As I said I log in using Meteor.loginWithPassword which isn’t returning an error. Meteor.userId() is set correctly after logging in.

I have attempted while connected to a MongoDB (with users of course), and without connecting the project and using the local mongo.

Can you share your code?

This is the login function that was working in version 1.11

        Meteor.loginWithPassword(this.email, this.password, (err) => {
          if (err) {
            let message = err.reason
            this.$toast.show(message, 'Error', this.$toast_opts.error)
            this.loader = false
          } else {
            if (Meteor.user().profile.active) {
              this.loader = false
              if (Meteor.user().profile.activated) {
                if (Meteor.user().profile.role.toLowerCase() !== 'user') {
                  if (Meteor.user().profile.role.toLowerCase() === 'work center') {
                    this.$router.push({
                      path: `/workcenter/${Meteor.user().profile.workcenter_id}`
                    })
                  } else {
                    this.$router.push({
                      path: '/workfloor'
                    })
                  }
                } else {
                  this.$router.push({
                    path: '/'
                  })
                }
              } else {
                this.set_password = true
              }
            } else {
              this.loader = false
              let message = 'Your account has been deactivated. Please contact an admin for more information.'
              this.$toast.show(message, 'Error', this.$toast_opts.error)
              Meteor.logout()
            }
          }

Not sure why it was working before, but Meteor.user() takes time to be populated from a subscription after a successful login.

You need to handle login using a reactive container

Right, even if I bypass all those post login checks and continue to the site anywhere Meteor.user() is used throughout the entire project it is undefined. Letting a page sit and trying to console log it with a button click at anytime it always comes back undefined.

How do you go to another location of the app? Through the URL? If yes, then you are encountering the same issue. Meteor.user() is a reactive data source and it takes time on loading the app before the subscription happens.

Again, you need to handle Meteor.user() using a reactive container

I’m using Vue and vue-router. Using this.$router.push({ path: '/' }) which goes to the homepage. On the homepage I have added a button that calls a 1 line function console.log(Meteor.user()) It does not matter how long I wait, or even by doing setInterval(() => { console.log(Meteor.user() }, 1000) Meteor.user() is not being defined. I understand that it takes time to be defined as I’ve had to implement role locks on some pages.

  beforeRouteEnter(to, from, next) {
    function userDefined() {
      if (typeof Meteor.user() !== 'undefined') {
        if (to.meta.roles.includes(Meteor.user().profile.role.toLowerCase())) {
          next()
        } else {
          next({
            path: '/*'
          })
        }
      } else {
        setTimeout(() => {
          userDefined()
        }, 250);
      }
    }

    userDefined()
  },

In your login method above wherein you check Meteor.user() in a callback for Meteor.loginWithPassword(), you are calling Meteor.logout() on the else clause. So technically, you are logging the user out right after login.

You can try commenting the Meteor.logout() line and check the other pages again

Ok I tried with this as the callback:

if (err) {
  console.log(err)
} else {
  this.$router.push( { path: '/' } )
}

I have this running on a button click on /

setInterval(() => {
  console.log(Meteor.user())
  if (Meteor.user()) {
    clearInterval()
  }
}, 1000)

I have it running now, so far after 5 minutes it has remained undefined.

Do you have your logged in user explicitly published from the server? Only profile is published by default

At the time I was able to find a work around since Meteor.userId() was still being defined I could pull the user from the db and keep it in the store. However, I have now found why Meteor.User() was undefined, and that’s because Meteor does not see the user as logged in. I discovered this while trying to call Accounts.changePassword and receiving the error of no user logged in. It appears even though My call to Meteor.loginWithPassword is not returning an error, and a loginToken is being created the user is still not being logged in?

The project has also since been updated to 2.0.

Furthermore, I haven’t made any changes to the default accounts packages. I verified files that were added by others working on the project, and could find no changes that should effect the publication. I’ve looked through and could not see and subscriptions that could be overwriting it. Are there any other common reasons that the default publication stops working? Are there any chances of this being connected to babel/webpack?

Could _id being stored as a string and not ObjectId effect this?

Hey @horstketterm , this is a little late for you probably, but I’ve been looking at the change logs to check what changes my app might experience when I make some updates.

Check it out and report back here. It looks like it was a new feature released in the accounts-base@1.7.1 package as it rolled to 1.7.1 on Dec. 4th 2020 which was included in the Meteor v1.12 update, so that would make a lot of sense.

Anyway, check out the Meteor v1.12 release notes here:
https://docs.meteor.com/changelog.html#v11220201204

accounts-base@1.7.1 adds the ability to define default user fields published on login. #11118

In #11118 it looks like you have to define the published fields instead of relying on what was before the Meteor defaults. There are some benefits that you can add extra fields if you need them too.


// username, profile, and emails used to be typical default fields

Accounts.setDefaultPublishFields({
    username: 1, 
    profile: 1, 
    emails: 1,
    'foo.bar': 1 // optional extra fields
});

I’ll be testing this myself soon, but I’m curious to know if adding the Accounts.setDefaultPublishFields() works for you.

//////// Updated /////////

@horstketterm After looking at the comments from @menelik it seems this is unlikely your root cause. I also use Vue with my Meteor app, and you want to make sure you use something like:

// in any Vue component file

meteor: {

  userDetails() {
    if(this.$subReady){
       console.log(Meteor.user());
    }
  }

  // other subs here
}

Accounts.setDefaultPublishFields() might not solve this issue, as without calling it the default fields are picked for publication. Accounts.setDefaultPublishFields() just makes it possible to extend/change the default fields. This would otherwise be only possible with a separate publication (a waste of ressources).

1 Like

@horstketterm

It seems to me that something with the user publication is generally not working. Have you debugged the websocket messages? You should see something like this:

image