sequelize/sequelize · error · Error

The "through" option is not available in hasMany. N:M associ

Error message

The "through" option is not available in hasMany. N:M associations are defined using belongsToMany instead.

What it means

Many-to-many (N:M) associations must use `belongsToMany`, not `hasMany`. The HasMany constructor (has-many.ts:127) checks `'through' in options` and throws an Error if present, because a `through` option on hasMany is a common mistake — hasMany is one-to-many with a foreign key on the target, not a join table.

Source

Thrown at packages/core/src/associations/has-many.ts:128

    target: ModelStatic<T>,
    options: NormalizedHasManyOptions<SourceKey, TargetKey>,
    parent?: Association,
    inverse?: BelongsToAssociation<T, S, TargetKey, SourceKey>,
  ) {
    if (options.sourceKey && !source.getAttributes()[options.sourceKey]) {
      throw new Error(
        `Unknown attribute "${options.sourceKey}" passed as sourceKey, define this attribute on model "${source.name}" first`,
      );
    }

    if ('keyType' in options) {
      throw new TypeError(
        'Option "keyType" has been removed from the BelongsTo\'s options. Set "foreignKey.type" instead.',
      );
    }

    if ('through' in options) {
      throw new Error(
        'The "through" option is not available in hasMany. N:M associations are defined using belongsToMany instead.',
      );
    }

    super(secret, source, target, options, parent);

    this.inverse =
      inverse ??
      BelongsToAssociation.associate(
        secret,
        target,
        source,
        removeUndefined({
          as: options.inverse?.as,
          scope: options.inverse?.scope,
          foreignKey: options.foreignKey,
          targetKey: options.sourceKey,
          foreignKeyConstraints: options.foreignKeyConstraints,

View on GitHub (pinned to 7e1deec499)

Solutions

  1. Switch to `belongsToMany`: `User.belongsToMany(Project, { through: 'UserProject' })`.
  2. If you truly want one-to-many, remove the `through` option and let the FK live on the target.

Example fix

// before
User.hasMany(Project, { through: 'UserProject' });

// after
User.belongsToMany(Project, { through: 'UserProject' });
Defensive patterns

Strategy: type-guard

Type guard

function isHasManyWithThrough(options) {
  return 'through' in options;
}
if (isHasManyWithThrough(opts)) {
  throw new Error('hasMany does not support through; use belongsToMany for N:M');
}

Prevention

When it happens

Trigger: `User.hasMany(Project, { through: 'UserProject' })` — passing a join table to a one-to-many association.

Common situations: Coming from Sequelize v3/v4 where `hasMany` with `through` was historically (mis)used; confusing one-to-many with many-to-many; copy-pasting from a belongsToMany example.

Related errors


AI-assisted analysis of sequelize/sequelize@7e1deec499 (2026-08-03). Data as JSON: /data/errors/db7b964202732aea.json. Report an issue: GitHub.