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
- Switch to `belongsToMany`: `User.belongsToMany(Project, { through: 'UserProject' })`.
- 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
- Reserve `through` exclusively for belongsToMany.
- When migrating from old Sequelize, audit hasMany calls for `through`.
- Use TypeScript — HasManyOptions intentionally omits `through`.
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
- The "timestamps" option in belongsToMany has been renamed to
- The "uniqueKey" option in belongsToMany has been renamed to
- BelongsToMany associations automatically create the correspo
- BelongsToMany: Option "through.unique" can only be used if t
- ${source.name}.belongsToMany(${target.name}) requires a thro
AI-assisted analysis of sequelize/sequelize@7e1deec499 (2026-08-03).
Data as JSON: /data/errors/db7b964202732aea.json.
Report an issue: GitHub.