{"id":"e6c874d79084e7c4","repo":"sequelize/sequelize","slug":"invalid-option-received-for-inverse-type-opti","errorCode":null,"errorMessage":"Invalid option received for \"inverse.type\": ${options.inverse.type} is not recognised. Expected \"hasMany\" or \"hasOne\"","messagePattern":"Invalid option received for \"inverse\\.type\": (.+?) is not recognised\\. Expected \"hasMany\" or \"hasOne\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/associations/belongs-to.ts","lineNumber":242,"sourceCode":"        as: options.inverse.as,\n        scope: options.inverse?.scope,\n        sourceKey: options.targetKey,\n        inverse: undefined,\n      });\n\n      delete passDown.targetKey;\n\n      switch (options.inverse.type) {\n        case 'hasMany':\n          HasManyAssociation.associate(secret, target, source, passDown, this, this);\n          break;\n\n        case 'hasOne':\n          HasOneAssociation.associate(secret, target, source, passDown, this, this);\n          break;\n\n        default:\n          throw new Error(\n            `Invalid option received for \"inverse.type\": ${options.inverse.type} is not recognised. Expected \"hasMany\" or \"hasOne\"`,\n          );\n      }\n    }\n  }\n\n  static associate<\n    S extends Model,\n    T extends Model,\n    SourceKey extends AttributeNames<S>,\n    TargetKey extends AttributeNames<T>,\n  >(\n    secret: symbol,\n    source: ModelStatic<S>,\n    target: ModelStatic<T>,\n    options: BelongsToOptions<SourceKey, TargetKey> = {},\n    parent?: Association<any>,\n  ): BelongsToAssociation<S, T, SourceKey, TargetKey> {","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/sequelize/sequelize/blob/7e1deec499d5afbb8d1877c2f4d545cead1214ec/packages/core/src/associations/belongs-to.ts#L224-L260","documentation":"BelongsTo supports an `inverse` option that auto-creates the back-reference; `inverse.type` must be either `'hasMany'` or `'hasOne'`. In the constructor (belongs-to.ts:232) a switch on `options.inverse.type` falls through to a default that throws an Error for any other value. This is a defensive check for an invalid/typo'd inverse type.","triggerScenarios":"`Comment.belongsTo(Post, { inverse: { type: 'belongsToMany' } })` or `inverse: { type: 'hasManyy' }` (typo) or any string other than the two allowed.","commonSituations":"Misunderstanding that the inverse of a belongsTo can only be hasMany or hasOne (not belongsToMany or another belongsTo); typo; passing a value from a generic variable.","solutions":["Use `inverse: { type: 'hasMany' }` for a one-to-many back-reference.","Use `inverse: { type: 'hasOne' }` for a one-to-one back-reference.","Remove the `inverse` option if you don't need an auto-created back-association."],"exampleFix":"// before\nComment.belongsTo(Post, { inverse: { type: 'belongsToMany' } });\n\n// after\nComment.belongsTo(Post, { inverse: { type: 'hasMany', as: 'comments' } });","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"const ALLOWED = new Set(['hasMany', 'hasOne']);\nfunction isValidInverseType(options) {\n  return !options.inverse || options.inverse.type === undefined || ALLOWED.has(options.inverse.type);\n}\nif (!isValidInverseType(opts)) {\n  throw new Error(`inverse.type must be 'hasMany' or 'hasOne'`);\n}","tryCatchPattern":null,"preventionTips":["Remember the inverse of a belongsTo can only be hasMany or hasOne — never belongsToMany.","Use TypeScript's `BelongsToOptions` which types `inverse.type` as the union.","Centralise inverse-type strings as constants to avoid typos."],"tags":["belongs-to","inverse","association-type","validation"],"analyzedSha":"7e1deec499d5afbb8d1877c2f4d545cead1214ec","analyzedAt":"2026-08-03T18:58:44.549Z","schemaVersion":2}