sequelize: Cannot read property 'name' of undefined when associating with hasMany

Issue Description

I have User and Message models, and I am attempting to associate them. User is supposed to have many Message and Message belongs to User. What’s happening is that hasMany is throwing some errors I cannot figure out why, and what’s more maddening is that I had already used a few months ago the way things are now, but this time it decided to not work.

StackOverflow / Slack attempts

https://stackoverflow.com/questions/58934011/sequelize-typeerror-cannot-read-property-name-of-undefined-between-a-1-rel

Additional context

User migration and class:

module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.createTable('users', {
      id: {
        type: Sequelize.INTEGER,
        autoIncrement: true,
        primaryKey: true,
        allowNull: false
      },
      username: {
        type: Sequelize.STRING,
        unique: true,
        allowNull: false
      },
      first_name: {
        type: Sequelize.STRING,
        allowNull: false
      },
      middle_name: {
        type: Sequelize.STRING
      },
      last_name: {
        type: Sequelize.STRING,
        allowNull: false
      },
      created_at: {
        type: Sequelize.DATE,
        allowNull: false
      },
      updated_at: {
        type: Sequelize.DATE,
        allowNull: false
      }
    })
  },

  down: queryInterface => {
    return queryInterface.dropTable('users')
  }
}
import Sequelize, { Model } from 'sequelize'

class User extends Model {
  static init(sequelize) {
    super.init(
      {
        username: Sequelize.STRING,
        first_name: Sequelize.STRING,
        middle_name: Sequelize.STRING,
        last_name: Sequelize.STRING
      },
      {
        sequelize
      }
    )

    return this
  }

  static associate(models) {
    this.hasMany(models.Message)
  }

  static async findByUsername(username) {
    return User.findOne({ where: { username } })
  }
}

export default User

Message migration and model:

module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.createTable('messages', {
      id: {
        type: Sequelize.INTEGER,
        autoIncrement: true,
        primaryKey: true,
        allowNull: false
      },
      user_id: {
        type: Sequelize.INTEGER,
        references: { model: 'users', key: 'id' },
        onUpdate: 'CASCADE',
        onDelete: 'CASCADE',
        allowNull: false
      },
      content: {
        type: Sequelize.STRING,
        allowNull: false
      },
      created_at: {
        type: Sequelize.DATE,
        allowNull: false
      },
      updated_at: {
        type: Sequelize.DATE,
        allowNull: false
      }
    })
  },

  down: queryInterface => {
    return queryInterface.dropTable('messages')
  }
}
import Sequelize, { Model } from 'sequelize'

class Message extends Model {
  static init(sequelize) {
    super.init(
      {
        user_id: Sequelize.INTEGER,
        content: Sequelize.STRING
      },
      {
        sequelize
      }
    )

    return this
  }

  static associate(models) {
    this.belongsTo(models.User, { foreignKey: 'user_id' })
  }
}

export default Message

Database class where things get initialized:

import Sequelize from 'sequelize'
import config from '../config/database'
import models from '../models'

class Database {
  constructor() {
    this.init()
  }

  init() {
    this.connection = new Sequelize(config)

    Object.keys(models).forEach(model => {
      models[model].init(this.connection)

      if ('associate' in models[model]) {
        models[model].associate(models)
      }
    })
  }
}

export default new Database()

models.js file where the models are imported and exported (GraphQL context):

import User from './User'
import Message from './Message'

export default {
  User,
  Message
}

Error when starting the server with npm start:

this.as = this.target.options.name.plural;
                                    ^

TypeError: Cannot read property 'name' of undefined
    at new HasMany (/home/gabriel/Workspace/apollo-server-sample/node_modules/sequelize/lib/associations/has-many.js:51:37)
    at Function.hasMany (/home/gabriel/Workspace/apollo-server-sample/node_modules/sequelize/lib/associations/mixin.js:34:25)
    at Function.associate (/home/gabriel/Workspace/apollo-server-sample/src/models/User.js:21:10)
    at forEach (/home/gabriel/Workspace/apollo-server-sample/src/database/index.js:17:23)
    at Array.forEach (<anonymous>)
    at Database.init (/home/gabriel/Workspace/apollo-server-sample/src/database/index.js:13:25)
    at new Database (/home/gabriel/Workspace/apollo-server-sample/src/database/index.js:7:10)
    at Object.<anonymous> (/home/gabriel/Workspace/apollo-server-sample/src/database/index.js:23:16)
    at Module._compile (internal/modules/cjs/loader.js:956:30)
    at Module._compile (/home/gabriel/Workspace/apollo-server-sample/node_modules/pirates/lib/index.js:99:24)
    at Module._extensions..js (internal/modules/cjs/loader.js:973:10)
    at Object.newLoader [as .js] (/home/gabriel/Workspace/apollo-server-sample/node_modules/pirates/lib/index.js:104:7)
    at Module.load (internal/modules/cjs/loader.js:812:32)
    at Function.Module._load (internal/modules/cjs/loader.js:724:14)
    at Module.require (internal/modules/cjs/loader.js:849:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at Object.<anonymous> (/home/gabriel/Workspace/apollo-server-sample/src/app.js:7:1)
    at Module._compile (internal/modules/cjs/loader.js:956:30)
    at Module._compile (/home/gabriel/Workspace/apollo-server-sample/node_modules/pirates/lib/index.js:99:24)
    at Module._extensions..js (internal/modules/cjs/loader.js:973:10)
    at Object.newLoader [as .js] (/home/gabriel/Workspace/apollo-server-sample/node_modules/pirates/lib/index.js:104:7)
    at Module.load (internal/modules/cjs/loader.js:812:32)
[nodemon] app crashed - waiting for file changes before starting...

Issue Template Checklist

Is this issue dialect-specific?

  • No. This issue is relevant to Sequelize as a whole.
  • Yes. This issue only applies to the following dialect(s): XXX, YYY, ZZZ
  • I don’t know.

Would you be willing to resolve this issue by submitting a Pull Request?

  • Yes, I have the time and I know how to start.
  • Yes, I have the time but I don’t know how to start, I would need guidance.
  • No, I don’t have the time, although I believe I could do it if I had the time…
  • No, I don’t have the time and I wouldn’t even know how to start.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 15 (5 by maintainers)

Most upvoted comments

FIGURED IT OUT

@mfgabriel92 and I had the same flaw in our database initialization code.

Object.keys(models).forEach(model => {
  models[model].init(this.connection)

  if ('associate' in models[model]) {
    models[model].associate(models)
   }
 })

If one of the dependent models has not been init-ed, then any calls to association methods will fail. You can fix this with one loop to call init() and another to call associate, i.e.

Object.keys(models).forEach(model => {
  models[model].init(this.connection)
 })

Object.keys(models).forEach(model => {
  if ('associate' in models[model]) {
    models[model].associate(models)
  }
})

Confirmed the failure in the SSCCE by writing in a similar structure. Thanks @papb for helping me troubleshoot.

I have the same problem the message is node_modules/sequelize/lib/associations/has-one.js:31 this.as = this.target.options.name.singular; ^ TypeError: Cannot read property ‘name’ of undefined

I have no idea what to do, i tried a lot of different things, but nothing works in this case.
If i found the error ill come back here to say how fix!

Under the use case provided by the SSCCE, yes.

Now I have to figure out how my usage differs from this bare bones case, and if the root cause is misuse on my part, or a valid use case that is not tested by your reproduction test harness.