[GH-ISSUE #6525] @better-auth/cli generate: Duplicate relation keys when plugin schema has multiple foreign keys to same table #10541

Closed
opened 2026-04-13 06:45:15 -05:00 by GiteaMirror · 2 comments
Owner

Originally created by @N0SAFE on GitHub (Dec 4, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/6525

Is this suited for github?

Yes, this is suited for github

To Reproduce

  1. Create a custom plugin with multiple foreign keys referencing the same table (e.g., user)
  2. Run @better-auth/cli generate to generate the Drizzle schema

Plugin schema example:

export const invitePlugin = <TRoles extends string>(options: InvitePluginOptions<TRoles>) => {
  return {
    id: "invite",
    // ... endpoints omitted for brevity
    schema: {
      invite: {
        fields: {
          token: { type: "string", unique: true, required: true },
          email: { type: "string", required: true },
          role: { type: "string", required: true },
          createdAt: { type: "date", defaultValue: () => new Date() },
          expiresAt: { type: "date", required: true },
          usedAt: { type: "date", required: false },
          // First FK to user table
          createdByUserId: {
            type: "string",
            required: false,
            fieldName: "created_by_user_id",
            references: { model: "user", field: "id", onDelete: "set null" },
          },
          // Second FK to user table
          invitedUserId: {
            type: "string",
            required: true,
            fieldName: "invited_user_id",
            references: { model: "user", field: "id", onDelete: "cascade" },
          },
        },
      },
    },
  } satisfies BetterAuthPlugin;
};

Current vs. Expected behavior

Current behavior

The CLI generates duplicate object keys in the relations, which causes TypeScript errors:

// Generated userRelations - DUPLICATE KEY "invites"
export const userRelations = relations(user, ({ one, many }) => ({
  sessions: many(session),
  accounts: many(account),
  invites: many(invite),  // ← First occurrence
  invites: many(invite),  // ← DUPLICATE - TypeScript error!
  // ...
}));

// Generated inviteRelations - DUPLICATE KEY "user"
export const inviteRelations = relations(invite, ({ one }) => ({
  user: one(user, {
    fields: [invite.created_by_user_id],
    references: [user.id],
  }),
  user: one(user, {  // ← DUPLICATE - TypeScript error!
    fields: [invite.invited_user_id],
    references: [user.id],
  }),
}));

TypeScript error:

An object literal cannot have multiple properties with the same name.ts(1117)

Expected behavior

The CLI should generate disambiguated relation names using relationName (as per Drizzle ORM documentation):

// Expected userRelations - UNIQUE KEYS
export const userRelations = relations(user, ({ one, many }) => ({
  sessions: many(session),
  accounts: many(account),
  createdInvites: many(invite, { relationName: 'createdBy' }),
  invitedAsInvites: many(invite, { relationName: 'invitedUser' }),
  // ...
}));

// Expected inviteRelations - UNIQUE KEYS with relationName
export const inviteRelations = relations(invite, ({ one }) => ({
  createdByUser: one(user, {
    fields: [invite.created_by_user_id],
    references: [user.id],
    relationName: 'createdBy',
  }),
  invitedUser: one(user, {
    fields: [invite.invited_user_id],
    references: [user.id],
    relationName: 'invitedUser',
  }),
}));

What version of Better Auth are you using?

1.4.4

System info

{
  "system": {
    "platform": "linux",
    "arch": "x64"
  },
  "node": {
    "version": "v20.x",
    "env": "development"
  },
  "packageManager": {
    "name": "bun",
    "version": "1.2.14"
  },
  "databases": [
    {
      "name": "drizzle-orm",
      "version": "^0.39.3"
    },
    {
      "name": "postgres",
      "version": "PostgreSQL 16"
    }
  ],
  "betterAuth": {
    "version": "^1.4.4"
  }
}

Which area(s) are affected?

  • CLI (@better-auth/cli)
  • Drizzle adapter/schema generation

Additional context

  • The table columns and foreign keys are generated correctly - only the Drizzle relations have this bug
  • This makes it impossible to use Drizzle's relational query builder (db.query.invite.findMany({ with: { createdByUser: true, invitedUser: true } })) without manually fixing the generated file
  • The workaround is to manually edit the generated schema file after each generate run, but this defeats the purpose of auto-generation
  • #4479 - "drizzle integration doesn't create relations" (different issue, but related to relations)
  • #6198 - "@better-auth/cli generate: drizzle faulty relation name" (similar CLI generation bug)

Suggested fix

When generating relations, the CLI should:

  1. Detect when multiple foreign keys reference the same table
  2. Generate unique relation names derived from the field names (e.g., createdByUserIdcreatedByUser)
  3. Add relationName property to disambiguate as per Drizzle ORM requirements
Originally created by @N0SAFE on GitHub (Dec 4, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/6525 ## Is this suited for github? Yes, this is suited for github ## To Reproduce 1. Create a custom plugin with multiple foreign keys referencing the same table (e.g., `user`) 2. Run `@better-auth/cli generate` to generate the Drizzle schema **Plugin schema example:** ```typescript export const invitePlugin = <TRoles extends string>(options: InvitePluginOptions<TRoles>) => { return { id: "invite", // ... endpoints omitted for brevity schema: { invite: { fields: { token: { type: "string", unique: true, required: true }, email: { type: "string", required: true }, role: { type: "string", required: true }, createdAt: { type: "date", defaultValue: () => new Date() }, expiresAt: { type: "date", required: true }, usedAt: { type: "date", required: false }, // First FK to user table createdByUserId: { type: "string", required: false, fieldName: "created_by_user_id", references: { model: "user", field: "id", onDelete: "set null" }, }, // Second FK to user table invitedUserId: { type: "string", required: true, fieldName: "invited_user_id", references: { model: "user", field: "id", onDelete: "cascade" }, }, }, }, }, } satisfies BetterAuthPlugin; }; ``` ## Current vs. Expected behavior ### Current behavior The CLI generates **duplicate object keys** in the relations, which causes TypeScript errors: ```typescript // Generated userRelations - DUPLICATE KEY "invites" export const userRelations = relations(user, ({ one, many }) => ({ sessions: many(session), accounts: many(account), invites: many(invite), // ← First occurrence invites: many(invite), // ← DUPLICATE - TypeScript error! // ... })); // Generated inviteRelations - DUPLICATE KEY "user" export const inviteRelations = relations(invite, ({ one }) => ({ user: one(user, { fields: [invite.created_by_user_id], references: [user.id], }), user: one(user, { // ← DUPLICATE - TypeScript error! fields: [invite.invited_user_id], references: [user.id], }), })); ``` **TypeScript error:** ``` An object literal cannot have multiple properties with the same name.ts(1117) ``` ### Expected behavior The CLI should generate **disambiguated relation names** using `relationName` (as per [Drizzle ORM documentation](https://orm.drizzle.team/docs/relations#disambiguating-relations)): ```typescript // Expected userRelations - UNIQUE KEYS export const userRelations = relations(user, ({ one, many }) => ({ sessions: many(session), accounts: many(account), createdInvites: many(invite, { relationName: 'createdBy' }), invitedAsInvites: many(invite, { relationName: 'invitedUser' }), // ... })); // Expected inviteRelations - UNIQUE KEYS with relationName export const inviteRelations = relations(invite, ({ one }) => ({ createdByUser: one(user, { fields: [invite.created_by_user_id], references: [user.id], relationName: 'createdBy', }), invitedUser: one(user, { fields: [invite.invited_user_id], references: [user.id], relationName: 'invitedUser', }), })); ``` ## What version of Better Auth are you using? 1.4.4 ## System info ```json { "system": { "platform": "linux", "arch": "x64" }, "node": { "version": "v20.x", "env": "development" }, "packageManager": { "name": "bun", "version": "1.2.14" }, "databases": [ { "name": "drizzle-orm", "version": "^0.39.3" }, { "name": "postgres", "version": "PostgreSQL 16" } ], "betterAuth": { "version": "^1.4.4" } } ``` ## Which area(s) are affected? - CLI (`@better-auth/cli`) - Drizzle adapter/schema generation ## Additional context - The **table columns and foreign keys are generated correctly** - only the Drizzle relations have this bug - This makes it impossible to use Drizzle's relational query builder (`db.query.invite.findMany({ with: { createdByUser: true, invitedUser: true } })`) without manually fixing the generated file - The workaround is to manually edit the generated schema file after each `generate` run, but this defeats the purpose of auto-generation ### Related issues - #4479 - "drizzle integration doesn't create relations" (different issue, but related to relations) - #6198 - "@better-auth/cli generate: drizzle faulty relation name" (similar CLI generation bug) ### Suggested fix When generating relations, the CLI should: 1. Detect when multiple foreign keys reference the same table 2. Generate unique relation names derived from the field names (e.g., `createdByUserId` → `createdByUser`) 3. Add `relationName` property to disambiguate as per Drizzle ORM requirements
GiteaMirror added the lockedbug labels 2026-04-13 06:45:15 -05:00
Author
Owner

@better-auth-agent[bot] commented on GitHub (Dec 4, 2025):

Hi there! Thank you for raising this issue. Based on your description, the CLI is currently generating duplicate keys in the Drizzle relations when your custom plugin defines multiple foreign keys to the same table. This results in TypeScript errors due to duplicated object keys (e.g., duplicate “invites” in userRelations and duplicate “user” in inviteRelations).

The expected behavior is to have unique, disambiguated relation names by incorporating a relationName property. For example, instead of duplicating “invites” or “user,” the CLI should generate keys like “createdInvites” (or “createdBy”) and “invitedUser” respectively, following the approach outlined in Drizzle’s documentation to disambiguate relations [1].

For now, as a workaround, you can manually adjust the generated schema file after running the CLI. We are aware of the issue (related to similar reports already tracked) and are investigating a fix for a coming release.

Tag @better-auth-agent if you would like an answer from the Agent.

Do you have any additional questions or other challenges with your current setup we can help you with?

If you need more help, tag @better-auth-agent in a comment so I can respond.

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3612076371 --> @better-auth-agent[bot] commented on GitHub (Dec 4, 2025): Hi there! Thank you for raising this issue. Based on your description, the CLI is currently generating duplicate keys in the Drizzle relations when your custom plugin defines multiple foreign keys to the same table. This results in TypeScript errors due to duplicated object keys (e.g., duplicate “invites” in userRelations and duplicate “user” in inviteRelations). The expected behavior is to have unique, disambiguated relation names by incorporating a relationName property. For example, instead of duplicating “invites” or “user,” the CLI should generate keys like “createdInvites” (or “createdBy”) and “invitedUser” respectively, following the approach outlined in Drizzle’s documentation to disambiguate relations [[1]](https://github.com/better-auth/better-auth/issues/6446). For now, as a workaround, you can manually adjust the generated schema file after running the CLI. We are aware of the issue (related to similar reports already tracked) and are investigating a fix for a coming release. Tag @better-auth-agent if you would like an answer from the Agent. Do you have any additional questions or other challenges with your current setup we can help you with? _If you need more help, tag @better-auth-agent in a comment so I can respond._ <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) • [Discord](https://discord.gg/fG2XXEuQX3) • [GitHub](https://github.com/Skyvern-AI/Skyvern) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/fG2XXEuQX3) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/Skyvern-AI/Skyvern)
Author
Owner

@jslno commented on GitHub (Dec 4, 2025):

Duplicate #6296

<!-- gh-comment-id:3612369788 --> @jslno commented on GitHub (Dec 4, 2025): Duplicate #6296
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#10541