Why does Firebase return `undefined` when fetching the `uid`?

First Published: 16 August 2017
Updated on: 18 June 2019

Cannot read property uid of undefined

How many times have you seen that error message? (Be honest!).

I’ve seen it so many times (both on the console and my inbox) that I lost track of the exact number, but it’s probably embarrassingly high.

Today we’re going to go through why that error happens and the two things you need to keep in mind to never see it again.

Why does the user return as undefined (or even null)?

You know there’s a logged in user, you just logged in, heck, you can even see the user object in chrome dev tools.

Then why is it still returning undefined? There’s a straight answer to it. You’re fetching the user object BEFORE that object is ready to be used.

Now, this can happen because of several different reasons, but if you follow this 2 “rules” you won’t see that error again.

Rule #1: Move it out of the constructor()

This is the biggest culprit, having too many calls inside the constructor (not only the user call).

When you have something like:

constructor(){
  this.userId = firebase.auth().currentUser.uid
}

Over half of the time that page loads, the constructor is going to try to get the user before the user is ready, the app is blocking it because the page isn’t fully loaded, so you’re going to be trying to access uid of a property that just isn’t there yet.

The one way to fix it is to keep it inside one of angular’s lifecycle hooks, like ngOnInit().

constructor(){}

ngOnInit(){
  this.userId = firebase.auth().currentUser.uid
}

This way, ngOnInit() will wait until everything in the page is fully loaded before running, ensuring that firebase.auth().currentUser resolves the current user logged in.

Rule #2: Make it an Observable

There’s another approach you can take, that previous Firebase call we just made: firebase.auth().currentUser is synchronous. We can make it asynchronous by subscribing to the auth observable instead.

So depending on the library you’re using, the JavaScript SDK has onAuthStateChanged() and AngularFire2 has authState().

Instead of fetching the user synchronously, we can do:

// For AngularFire:
afAuth.authState.subscribe( user =>; {
  if (user) { this.userId = user.uid }
});

// For the JS SDK
firebase.auth().onAuthStateChanged( user =>; {
  if (user) { this.userId = user.uid }
});

That way, Ionic makes an asynchronous request to Firebase and ensures that it will have the user before trying to use its properties.

If you keep those two rules in mind whenever you’re dealing with auth states, you won’t have to worry about that annoying error again :)