Search code examples
javascriptnode.jssequelize.js

Sequelize relation errors: Cannot convert undefined or null to object


I am developing a webapp and using Sequelize to manage my database (Postgres). The User is always found and returns correctly, however finding the Credentials spits out:

TypeError: Cannot convert undefined or null to object
    at hasOwnProperty (<anonymous>)
    at credentials._paranoidClause (C:\bots\Trion\node_modules\sequelize\lib\model.js:176:65)
    at credentials.findAll (C:\bots\Trion\node_modules\sequelize\lib\model.js:1135:20)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async credentials.findOne (C:\bots\Trion\node_modules\sequelize\lib\model.js:1240:12)
    at async login (file:///C:/bots/Trion/routes/auth.js:77:21)

Here are my models:

User.js

import { DataTypes } from "sequelize";
import { sequelize } from './SQL.js';

const User = sequelize.define("user", {
    id: {
        type: DataTypes.INTEGER,
        autoIncrement: true,
        primaryKey: true,
        allowNull: false
    },
    anonymous: {
        type: DataTypes.BOOLEAN,
        allowNull: false,
        defaultValue: true
    },
    username: {
        type: DataTypes.STRING,
        allowNull: false,
        unique: true
    },
    avatarBlob: {
        type: DataTypes.BLOB
    }
}, {
    sequelize,
    tableName: "user",
    timestamps: true,
    createdAt: "createdAt",
    updatedAt: false,
    deletedAt: "deletedAt",
    paranoid: true
});

User.hasOne(Credentials, {
    sourceKey: 'id',
    foreignKey: 'userId',
    onUpdate: 'CASCADE',
    onDelete: 'CASCADE'
});
Credentials.belongsTo(User);

export { User };

Credentials.js

import { DataTypes } from "sequelize";
import { sequelize } from './SQL.js';
import { User } from './User.js';

const Credentials = sequelize.define("credentials", {
    userId: {
        type: DataTypes.INTEGER,
        unique: true,
        allowNull: false
    },
    password: {
        type: DataTypes.STRING,
        allowNull: false,
    },
    salt: {
        type: DataTypes.STRING,
        allowNull: false,
    }
}, {
    sequelize,
    tableName: "credentials",
    timestamps: true,
    createdAt: false,
    updatedAt: "updatedAt",
    deletedAt: false,
    paranoid: true
});

export { Credentials };

These two are 1:1 related, and it works when seen from a GUI client.

Here is the problem code:

let user = await User.findOne({ where: { username: payload.username } });
let creds = await Credentials.findOne({ where: { userId: user.id } });

What may be happening here? Everything looks ok according to the docs, and it's been driving me in circles for a good while now.

I have tried finding it through a raw query, which works as intended:

'SELECT * FROM credentials WHERE credentials."userId" = ' + user.id + ';'

I have also tried some specific Sequelize things, like:

await User.findOne({ where: { username: payload.username }, include: Credentials });

which spits out the same error, or:

await User.getCredentials();

which doesn't exist (but the docs suggest the function should be automatically generated?).


Solution

  • Found the answer myself by deeply debugging Sequelize, and what a silly mistake it was. Please don't disable the deletedAt column on your models if you're gonna leave paranoid mode on.