How I Fixed: TypeError: ‘null’ is not an object (evaluating ‘currentSpec.$injector’)

 

I hit upon a problem in testing an Angular project this week that had me stumped for a while. The problem was this:

Every time I ran the test suite as a whole, they failed.

But if I ran each test file on its own… individually, they would pass.

I find more and more of my time lately is spent dealing with these sorts of things – they aren’t ‘development’ tasks, just annoyances that keep me from doing the thing I enjoy most – writing code.

Anyway, here’s the error:

INFO [PhantomJS 1.9.8 (Linux 0.0.0)]: Connected on socket DGb_Xn6WLWQNnEEkUwtk with id 45807911
PhantomJS 1.9.8 (Linux 0.0.0) LOG: 'no config'
 
PhantomJS 1.9.8 (Linux 0.0.0) LOG: 'no config'
 
PhantomJS 1.9.8 (Linux 0.0.0) LOG: 'no config'
 
PhantomJS 1.9.8 (Linux 0.0.0) UrlManager should have get function FAILED
        TypeError: 'null' is not an object (evaluating 'currentSpec.$injector')
            at workFn (/tmp/7b8601aaed330a593345d271f7b468335eb33d59.browserify:23390:0 <- /my/project/node_modules/angular-mocks/angular-mocks.js:2330:0)
            at /my/project/node_modules/karma-jasmine/lib/boot.js:126
            at /my/project/node_modules/karma-jasmine/lib/adapter.js:171
            at http://localhost:9876/karma.js:182
            at http://localhost:9876/context.html:257
        TypeError: 'null' is not an object (evaluating 'currentSpec.$injector')
            at workFn (/tmp/7b8601aaed330a593345d271f7b468335eb33d59.browserify:23390:0 <- /my/project/node_modules/angular-mocks/angular-mocks.js:2330:0)
            at /my/project/node_modules/karma-jasmine/lib/boot.js:126
            at /my/project/node_modules/karma-jasmine/lib/adapter.js:171
            at http://localhost:9876/karma.js:182
            at http://localhost:9876/context.html:257
        TypeError: 'null' is not an object (evaluating 'currentSpec.$injector')
            at workFn (/tmp/7b8601aaed330a593345d271f7b468335eb33d59.browserify:23390:0 <- /my/project/node_modules/angular-mocks/angular-mocks.js:2330:0)
            at /my/project/node_modules/karma-jasmine/lib/boot.js:126
            at /my/project/node_modules/karma-jasmine/lib/adapter.js:171
            at http://localhost:9876/karma.js:182
            at http://localhost:9876/context.html:257
        TypeError: 'null' is not an object (evaluating 'currentSpec.$modules')
            at workFn (/tmp/7b8601aaed330a593345d271f7b468335eb33d59.browserify:23514:0 <- /my/project/node_modules/angular-mocks/angular-mocks.js:2454:0)
            at /my/project/node_modules/karma-jasmine/lib/boot.js:126
            at /my/project/node_modules/karma-jasmine/lib/adapter.js:171
            at http://localhost:9876/karma.js:182
            at http://localhost:9876/context.html:257
        TypeError: 'undefined' is not an object (evaluating 'UrlManager.get')
            at /tmp/7b8601aaed330a593345d271f7b468335eb33d59.browserify:42035:0 <- /my/project/src/components/UrlManager/spec/UrlManagerSpec.js:26:0
            at /my/project/node_modules/karma-jasmine/lib/boot.js:126
            at /my/project/node_modules/karma-jasmine/lib/adapter.js:171
            at http://localhost:9876/karma.js:182
            at http://localhost:9876/context.html:257
PhantomJS 1.9.8 (Linux 0.0.0) UrlManager should return object for the others FAILED
        TypeError: 'null' is not an object (evaluating 'currentSpec.$injector')
            at workFn (/tmp/7b8601aaed330a593345d271f7b468335eb33d59.browserify:23390:0 <- /my/project/node_modules/angular-mocks/angular-mocks.js:2330:0)
            at /my/project/node_modules/karma-jasmine/lib/boot.js:126
            at /my/project/node_modules/karma-jasmine/lib/adapter.js:171
            at http://localhost:9876/karma.js:182
            at http://localhost:9876/context.html:257
        TypeError: 'null' is not an object (evaluating 'currentSpec.$injector')
            at workFn (/tmp/7b8601aaed330a593345d271f7b468335eb33d59.browserify:23390:0 <- /my/project/node_modules/angular-mocks/angular-mocks.js:2330:0)
            at /my/project/node_modules/karma-jasmine/lib/boot.js:126
            at /my/project/node_modules/karma-jasmine/lib/adapter.js:171
            at http://localhost:9876/karma.js:182
            at http://localhost:9876/context.html:257
        TypeError: 'null' is not an object (evaluating 'currentSpec.$injector')
            at workFn (/tmp/7b8601aaed330a593345d271f7b468335eb33d59.browserify:23390:0 <- /my/project/node_modules/angular-mocks/angular-mocks.js:2330:0)
            at /my/project/node_modules/karma-jasmine/lib/boot.js:126
            at /my/project/node_modules/karma-jasmine/lib/adapter.js:171
            at http://localhost:9876/karma.js:182
            at http://localhost:9876/context.html:257
        TypeError: 'null' is not an object (evaluating 'currentSpec.$modules')
            at workFn (/tmp/7b8601aaed330a593345d271f7b468335eb33d59.browserify:23514:0 <- /my/project/node_modules/angular-mocks/angular-mocks.js:2454:0)
            at /my/project/node_modules/karma-jasmine/lib/boot.js:126
            at /my/project/node_modules/karma-jasmine/lib/adapter.js:171
            at http://localhost:9876/karma.js:182
            at http://localhost:9876/context.html:257
        TypeError: 'undefined' is not an object (evaluating 'UrlManager.get')
            at /tmp/7b8601aaed330a593345d271f7b468335eb33d59.browserify:42053:0 <- /my/project/src/components/UrlManager/spec/UrlManagerSpec.js:44:0
            at /my/project/node_modules/karma-jasmine/lib/boot.js:126
           at /my/project/node_modules/karma-jasmine/lib/adapter.js:171
            at http://localhost:9876/karma.js:182
            at http://localhost:9876/context.html:257
PhantomJS 1.9.8 (Linux 0.0.0): Executed 7 of 7 (2 FAILED) (0.415 secs / 0.026 secs)
 
=============================== Coverage summary ===============================
Statements   : 17.48% ( 482/2758 )
Branches     : 4.14% ( 40/967 )
Functions    : 4.65% ( 30/645 )
Lines        : 17.62% ( 477/2707 )
================================================================================
[13:41:23] 'test' errored after 8.21 s
[13:41:23] Error in plugin 'test'
Message:
    Karma test returned 1
blimpyboy@project-dev1:~/Development/project$ ^C
blimpyboy@project-dev1:~/Development/project$ ^C
blimpyboy@project-dev1:~/Development/project$ gulp test
[13:42:58] Warning: gulp version mismatch:
[13:42:58] Global gulp is 3.9.0
[13:42:58] Local gulp is 3.8.11
[13:42:59] Using gulpfile ~/Development/project/gulpfile.js
[13:42:59] Starting 'test'...
INFO [framework.browserify]: Paths to browserify
    /my/project/src/components/PubSub/spec/**/*.js
    /my/project/src/components/UrlManager/spec/**/*.js
INFO [framework.browserify]: Browserified in 6543ms, 6524kB
INFO [karma]: Karma v0.12.37 server started at http://localhost:9876/
INFO [launcher]: Starting browser PhantomJS
INFO [PhantomJS 1.9.8 (Linux 0.0.0)]: Connected on socket VrUi5MBGOl0J1oHWVKNw with id 50398227
PhantomJS 1.9.8 (Linux 0.0.0) LOG: 'no config'
 
PhantomJS 1.9.8 (Linux 0.0.0) LOG: 'no config'
 
PhantomJS 1.9.8 (Linux 0.0.0) LOG: 'no config'
 
PhantomJS 1.9.8 (Linux 0.0.0): Executed 7 of 7 SUCCESS (0.056 secs / 0.035 secs)
 
=============================== Coverage summary ===============================
Statements   : 20.01% ( 552/2758 )
Branches     : 5.07% ( 49/967 )
Functions    : 6.98% ( 45/645 )
Lines        : 20.21% ( 547/2707 )
================================================================================
[13:43:07] Finished 'test' after 8.1 s
blimpyboy@project-dev1:~/Development/project$

I’m aware the coverage isn’t so good – but actually this is not the true coverage as I’d stripped out a whole bunch of tests by bastardising the karma.conf.js file to try and isolate the problem. No… seriously, I promise 🙂

Anyway, it turned out that the solution to this was actually pretty simple.

Of course, nearly all solutions to programming problem seem simple once you have figured out the problem. Hindsight is such a wonderful thing.

But in this case, the problem was that a bunch of variables had been declared inside on the of describe blocks:

describe("SomeModule module", function () {

    beforeEach(angular.mock.module('Some.Module'));

    var angular = require('angular');
    var scope;
    require('../../../scripts/app.js');
    require('angular-mocks');

    var SomeModule;

And the solution was to simply move all the setup stuff outside of the describe block:

var angular = require('angular');
var scope;
require('../../../scripts/app.js');
require('angular-mocks');

var SomeModule;

describe("SomeModule module", function () {

    beforeEach(angular.mock.module('Some.Module'));

An easy fix.

The real annoyance here was that I went through this whole project alphabetically, and this particular module began with the letter ‘P’, so I’d been through over half the code before I spotted it. Hours I will never get back.

Still, it’s fixed now, and hopefully now you can save a few hours if you ever suffer from this problem yourself.

 

Why I Find JavaScript’s ES6 Destructuring So Fascinating

I spend a lot of time in PHP land.

PHP is a very useful and competent language, but I feel it’s fair to say it lacks somewhat in syntactical grace.

JavaScript’s ES6 on the other hand, is very elegant (to my eyes). This is a snippet from a React tutorial I have been following recently.

  const {
    isFetching,
    lastUpdated,
    items: posts
    } = postsBySubreddit[selectedSubreddit] || {
    isFetching: true,
    items: []
  };

There’s so much going on here.

As a recent migrant to ES6, I find this as intriguing as I do confusing.

The primary concept at work here is ES6 Destructuring. This is a really interesting technique to pull multiple pieces of data from arrays or objects in one go.

I found the concept initially confusing. I read this as a const  that is an object but has no variable name? Not quite.

It’s somewhat easier to understand this statement if we break it down one step further:

  const {
    isFetching,
    lastUpdated,
    items: posts
    } = postsBySubreddit[selectedSubreddit];

I still feel this is complicated for someone, like me, who is new to Destructuring.

Let’s take an even simpler example:

const {a} = {a: 1, b: 2};

This looks a bit easier, a bit more understandable, I feel.

Here we have a regular JavaScript object: {a: 1, b: 2}

We want to create ourselves a constant containing the value of a from this object. A test might illustrate this a little better than words:

it('is possible to grab "a" from our object', () => {
  const ourObject = {a: 1, b: 2};
  let a = ourObject.a; 
  assert.equal(a, 1);
});

Destructuring gives us a short hand notation for this same concept:

it('is possible to grab "a" from our object in a more concise way', () => {
  const {a} = {a: 1, b: 2};
  assert.equal(a, 1);
});

By using the same key name inside the {} ‘s as that which exists on the object, ES6 will go ahead and create us a constant, called a with the value of 1. It essentially pulls out the value from the object and creates a variable / constant for us. Two steps, combined into one. This is one of those things I have immediately started to miss the most when working in PHP.

But what if we don’t want the new constant to be called a, but we do want it to still contain the value of a. Of course, ES6 has you covered here too:

it('is possible to rename "a"', () => {
  const {a: somethingElse} = {a: 1, b: 2};
  assert.equal(somethingElse, 1);
});

Seems a little back to front, but it does make sense. Pull out a as we’ve already covered, and re-name it to somethingElse.

You can see this in action in the React tutorial snippet:

  const {
    isFetching,
    lastUpdated,
    items: posts
    } = postsBySubreddit[selectedSubreddit];

Here, items exists in the original data, and whilst we do want to use the value of items, we want to use a different reference for it – posts.

There are other things we could do with destructuring assignment, it really is quite an awesome concept.

Now we know about these two concepts, let’s take another look at the example:

  const {
    isFetching,
    lastUpdated,
    items: posts
    } = postsBySubreddit[selectedSubreddit];

So we can see both of the above (pulling out by name, and pull-out-and-rename) happening in one statement here.

I found the postsBySubreddit name really confused me. If you can, disregard the name, and simply think of it as an object:

someObject[dynamicKey]

Then for me, it becomes a little easier to reason about:

  it('is possible to use a dynamic key', () => {
    
    let dynamicKey = 'key2';

    const someObject = {
      key1: 'a',
      key2: 'b',
      key3: 'c'
    };
    
    assert.equal(someObject[dynamicKey], 'b');
  });

postsBySubreddit is simply an object with potentially multiple keys.Each key will be the name of a subreddit: ‘php’, ‘reactjs’, ‘programming’ and so on.

We aren’t hard-coding the value of the key we need. We are instead asking for a key using the variable named selectedSubreddit, or dynamicKey in my example.

Don’t just take my word for this though, do look at the code. Unfortunately, I can’t link directly to the line(s) in question, but a quick ctrl+f on the linked page for ‘postsBySubreddit’ will get you to where you need to be.

selectedSubreddit will be one of these keys / subreddits. And all subreddit data will be an array, called items. But because we know that destructuring can rename a property for us, we can take advantage of this to rename items to posts .

isFetching and lastUpdated are both straightforward (in as much as any of this is straightforward), in that they are keys we want to create constants for.

Phew, that’s a lot happening in one statement.

But, remember, we actually broke this line down even further:

  const {
    isFetching,
    lastUpdated,
    items: posts
    } = postsBySubreddit[selectedSubreddit] 
  || {
    isFetching: true,
    items: []
  };

At this stage, we are really only concerned with the bit we haven’t yet covered, so I’ve reformatted it slightly to make it more obvious.

So we’ve done all this destructuring… OR (||) if we are unable to access postsBySubreddit[selectedSubreddit]  then create two constants:

isFetching: true,
items: []

Which would leave lastUpdated as undefined.

But don’t just take my word for it. Have a play around with this code and get a feel for what it is doing. Destructuring is definitely something you will start using more and more, but it’s initially confusing for sure.

JavaScript is moving fast (although I have heard some say that this is slowing down) and if you’re still finding your feet with PHP (or any other language) then I’d advise not to dig to deeply into ES6 just yet.

I’d argue that the transition to ES6 is going to be so challenging for some developers that we may possibly end up in a Python 2 / 3 situation in JavaScript land in the next few years. Which is why I believe the current form of JavaScript will be around for years to come.

Whichever form of JavaScript you choose to use, take the time to dig into the more functional concepts of JavaScript. It will truly help your programming – including your PHP – skills grow.

Models not working in Loopback Passport Module

I’ve been having a heck of a time trying to get Passport, or more specifically, the Loopback Passport Component to work with my Strongloop API project.

I should say, this is an existing project into which I have installed the loopback passport component (npm i loopback-component-passport --save) rather than using the Loopback Passport Example – which I also have had plenty of problems with.

Today’s error was when loading the Strongloop Composer (v1.8.1), I could see my datasources, but the models were empty:

strongloop-loopback-empty-models-in-slc-arc

When opening up the Chrome developer tools > console, I could see this:

TypeError: Cannot read property 'dataSource' of undefined
    at Array. (model.services.js:179)
    at Object.forEach (angular.js:323)
    at model.services.js:161
    at angular-resource.js:627
    at processQueue (angular.js:13248)
    at angular.js:13264
    at Scope.parent.$get.Scope.$eval (angular.js:14466)
    at Scope.parent.$get.Scope.$digest (angular.js:14282)
    at Scope.scopePrototype.$digest (hint.js:1955)
    at Scope.parent.$get.Scope.$apply (angular.js:14571)

But Googling this error wasn’t coming up with much in the way of suggestions.

Another strange thing was that I could add in a new Model, save it, but then if I refreshed the page, it would disappear. The model itself had been created in the common/models dir. I could see the .js and .json files in my WebStorm project, and if I tried to create a new Model with the same name it wouldn’t let me. But the slc arc Composer just wouldn’t display them.

Though I cannot remember exactly how I was getting to this point, I was also infrequently seeing errors in the console, with this error message:

{"error":{"name":"Error","status":404,"message":"Unknown "DataSourceDefinition" id "undefined".","statusCode":404,"code":"MODEL_NOT_FOUND","stack":"Error: Unknown "DataSourceDefinition" id "undefined".\n    at Function.convertNullToNotFoundError (/usr/local/lib/node_modules/strongloop/node_modules/loopback/lib/persisted-model.js:81:17)\n    at invokeRestAfter (/usr/local/lib/node_modules/strongloop/node_modules/loopback/node_modules/strong-remoting/lib/rest-adapter.js:445:25)\n    at /usr/local/lib/node_modules/strongloop/node_modules/async/lib/async.js:607:21\n    at /usr/local/lib/node_modules/strongloop/node_modules/async/lib/async.js:246:17\n    at iterate (/usr/local/lib/node_modules/strongloop/node_modules/async/lib/async.js:146:13)\n    at /usr/local/lib/node_modules/strongloop/node_modules/async/lib/async.js:157:25\n    at /usr/local/lib/node_modules/strongloop/node_modules/async/lib/async.js:248:21\n    at /usr/local/lib/node_modules/strongloop/node_modules/async/lib/async.js:612:34\n    at /usr/local/lib/node_modules/strongloop/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:626:11\n    at execStack (/usr/local/lib/node_modules/strongloop/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:460:7)"}}

I’m leaving that in, in the hope that any future Googlers may save themselves some time.

My Fix

To get this working I ended up creating a brand new project (slc loopback) and then piece by piece, copying my existing project across and watching for where it broke.

It turns out it was largely the Passport module config that was breaking the project, so here are the relevant, working files:

Check your versions. Loopback changes a lot.

// package.json
{
  "name": "tester",
  "version": "1.0.0",
  "main": "server/server.js",
  "scripts": {
    "pretest": "jshint ."
  },
  "dependencies": {
    "compression": "^1.0.3",
    "cors": "^2.5.2",
    "errorhandler": "^1.1.1",
    "express-session": "^1.11.3",
    "loopback": "^2.14.0",
    "loopback-boot": "^2.6.5",
    "loopback-component-passport": "^1.5.0",
    "loopback-connector-mysql": "^2.2.0",
    "loopback-datasource-juggler": "^2.19.0",
    "passport-local": "^1.0.0",
    "passport-tumblr": "^0.1.2",
    "serve-favicon": "^2.0.1"
  },
  "optionalDependencies": {
    "loopback-explorer": "^1.1.0"
  },
  "devDependencies": {
    "jshint": "^2.5.6"
  },
  "repository": {
    "type": "",
    "url": ""
  },
  "description": "tester"
}

In the model-config.json, note the inclusion of "./node_modules/loopback-component-passport/lib/models" in the meta > sources, the UserCredential, and UserIdentity models:

// server/model-config.jsom
{
  "_meta": {
    "sources": [
      "loopback/common/models",
      "loopback/server/models",
      "../common/models",
      "./models",
      "./node_modules/loopback-component-passport/lib/models"
    ],
    "mixins": [
      "loopback/common/mixins",
      "loopback/server/mixins",
      "../common/mixins",
      "./mixins",
      "../node_modules/loopback-ds-timestamp-mixin"
    ]
  },
  "User": {
    "dataSource": "db",
    "public": true
  },
  "AccessToken": {
    "dataSource": "db",
    "public": false
  },
  "ACL": {
    "dataSource": "db",
    "public": false
  },
  "RoleMapping": {
    "dataSource": "db",
    "public": false
  },
  "Role": {
    "dataSource": "db",
    "public": false
  },
  "UserCredential": {
    "dataSource": "db",
    "public": false
  },
  "UserIdentity": {
    "dataSource": "db",
    "public": false
  },
  "user": {
    "dataSource": "db",
    "public": true
  },
  "userCredential": {
    "dataSource": "db",
    "public": true
  },
  "userIdentity": {
    "dataSource": "db",
    "public": true
  },
  "accessToken": {
    "dataSource": "db",
    "public": true
  },
  "acl": {
    "dataSource": "db",
    "public": true
  },
  "roleMapping": {
    "dataSource": "db",
    "public": true
  },
  "role": {
    "dataSource": "db",
    "public": true
  },
  "scope": {
    "dataSource": "db",
    "public": true
  }
}

Why the duplicates, e.g. User and user?

Well, you have to define the base model, and then your own model which extends the base. But both have to be defined.

This bit left me confused, so here are each of the relevant models for reference:

// common/models/access-token.json 
{
  "name": "accessToken",
  "plural": "accessTokens",
  "base": "AccessToken",
  "properties": {},
  "validations": [],
  "relations": {},
  "acls": [],
  "methods": []
}
// common/models/acl.json 
{
  "name": "acl",
  "plural": "acls",
  "base": "ACL",
  "properties": {},
  "validations": [],
  "relations": {},
  "acls": [],
  "methods": []
}
// common/models/role.json
{
  "name": "role",
  "plural": "roles",
  "base": "Role",
  "properties": {},
  "validations": [],
  "relations": {},
  "acls": [],
  "methods": []
}
// common/models/role-mapping.json
{
  "name": "roleMapping",
  "plural": "roleMappings",
  "base": "RoleMapping",
  "properties": {},
  "validations": [],
  "relations": {},
  "acls": [],
  "methods": []
}
// common/models/scope.json
{
  "name": "scope",
  "plural": "scopes",
  "base": "Scope",
  "properties": {},
  "validations": [],
  "relations": {},
  "acls": [],
  "methods": []
}
// common/models/user.json
{
  "name": "user",
  "plural": "users",
  "base": "User",
  "properties": {
    "accessTokens": {
      "type": "hasMany",
      "model": "accessToken",
      "foreignKey": "userId"
    },
    "identities": {
      "type": "hasMany",
      "model": "userIdentity",
      "foreignKey": "userId"
    },
    "credentials": {
      "type": "hasMany",
      "model": "userCredential",
      "foreignKey": "userId"
    }
  },
  "validations": [],
  "relations": {},
  "acls": [],
  "methods": []
}
// common/models/user-credential.json
{
  "name": "userCredential",
  "plural": "userCredentials",
  "base": "UserCredential",
  "properties": {},
  "validations": [],
  "relations": {
    "user": {
      "type": "belongsTo",
      "model": "user",
      "foreignKey": "userId"
    }
  },
  "acls": [],
  "methods": []
}
// common/models/user-identity.json
{
  "name": "userIdentity",
  "plural": "userIdentities",
  "base": "UserIdentity",
  "properties": {},
  "validations": [],
  "relations": {
    "user": {
      "type": "belongsTo",
      "model": "user",
      "foreignKey": "userId"
    }
  },
  "acls": [],
  "methods": []
}

Once the models are displaying again, feel free to change the datasources:

// server/datasources.json 
{
  "db": {
    "name": "db",
    "connector": "memory"
  },
  "mysql": {
    "host": "your.server.ip.here",
    "database": "dbname",
    "password": "dbpassword",
    "name": "mysql",
    "connector": "mysql",
    "user": "dbuser"
  }
}

Note, those are the settings created by Strongloop slc arc. If you enter them manually, using the data / fields in the manual, you may end up with duplicates – e.g. user and username.

My Loopback Passport Module Config

And lastly, and probably the most important is the server.js file.

// server/server.js
var loopback = require('loopback');
var boot = require('loopback-boot');

var app = module.exports = loopback();

var PassportConfigurator = require('loopback-component-passport').PassportConfigurator;
var passportConfigurator = new PassportConfigurator(app);

app.start = function() {
  // start the web server
  return app.listen(function() {
    app.emit('started');
    console.log('Web server listening at: %s', app.get('url'));
  });
};

// Bootstrap the application, configure models, datasources and middleware.
// Sub-apps like REST API are mounted via boot scripts.
boot(app, __dirname, function(err) {
  if (err) throw err;

  // start the server if `$ node server.js`
  if (require.main === module)
    app.start();
});

// Enable http session
app.use(loopback.session({ 
  secret: 'keyboard cat',  
  resave: true,
  saveUninitialized: true 
}));

// Load the provider configurations
var config = {};
try {
  config = require('./providers.json');
} catch(err) {
  console.error('Please configure your passport strategy in `providers.json`.');
  console.error('Copy `providers.json.template` to `providers.json` and replace the clientID/clientSecret values with your own.');
  process.exit(1);
}
// Initialize passport
passportConfigurator.init();

// Set up related models
passportConfigurator.setupModels({
  userModel: app.models.User,
  userIdentityModel: app.models.UserIdentity,
  userCredentialModel: app.models.UserCredential
});
// Configure passport strategies for third party auth providers
for(var s in config) {
  var c = config[s];
  c.session = c.session !== false;
  passportConfigurator.configureProvider(s, c);
}

The ordering here seems to be the most important part.

If your passport config tries to call the models before they are ready, that seems to cause a lot of problems. It sounds obvious in hindsight, but when you have a lot of things going on in your server.js file, sometimes it can be hard to see the wood for the trees.