[GH-ISSUE #5037] auth.api.removeTeamMember returns success but does not delete team membership record #10149

Closed
opened 2026-04-13 06:05:48 -05:00 by GiteaMirror · 6 comments
Owner

Originally created by @juninaba on GitHub (Oct 2, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/5037

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Call ‎auth.api.removeTeamMember.
  2. Observe the API response: 200 with ‎{ message: 'Team member removed successfully.' }.
  3. The record still exists and has not been deleted.

Current vs. Expected behavior

Current:
• ‎auth.api.removeTeamMember returns a success message and 200 status, but the team membership record remains in the database.

Expected:
• On success, the corresponding team membership record should be deleted from the database.

What version of Better Auth are you using?

v1.3.8

System info

{
  "system": {
    "platform": "darwin",
    "arch": "arm64",
    "version": "Darwin Kernel Version 25.0.0: Mon Aug 25 21:17:54 PDT 2025; root:xnu-12377.1.9~3/RELEASE_ARM64_T6041",
    "release": "25.0.0",
    "cpuCount": 14,
    "cpuModel": "Apple M4 Pro",
    "totalMemory": "48.00 GB",
    "freeMemory": "2.07 GB"
  },
  "node": {
    "version": "v24.7.0",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "11.5.1"
  },
  "frameworks": null,
  "databases": null,
  "betterAuth": {
    "version": "Unknown",
    "config": null
  }
}

Which area(s) are affected? (Select all that apply)

Backend

Auth config (if applicable)

import { betterAuth } from "better-auth"
export const auth = betterAuth({
  database: prismaAdapter(client, {
    provider: 'postgresql'
  }),
  emailAndPassword: {
    enabled: true,
    requireEmailVerification: true,
    sendResetPassword: async ({ user, url }) => {
      const { subject, text } = buildPasswordResetEmail(user.email, url);
      await sendEmail({ to: user.email, subject, text });
    },
  },
  emailVerification: {
    sendOnSignUp: true,
    sendOnSignIn: true,
    autoSignInAfterVerification: true,
    sendVerificationEmail: async ({ user, url }) => {
      const { subject, text } = buildVerificationEmail(user.email, url);
      await sendEmail({ to: user.email, subject, text });
    },
  },
  socialProviders: {
    google: {
      prompt: "select_account",
      clientId: process.env.GOOGLE_CLIENT_ID || '',
      clientSecret: process.env.GOOGLE_CLIENT_SECRET || '',
    }
  },
  plugins: [
    organization({
      teams: {
        enabled: true
      },
      requireEmailVerificationOnInvitation: true,
      async sendInvitationEmail(data) {
        const inviteLink = `/api/accept-invitation/${data.id}`;
        const { subject, text } = buildInvitationEmail(data.email, data.inviter.user.name, inviteLink);
        await sendEmail({ to: data.email, subject, text });
      },
    }),
    twoFactor(),
  ]
});

Additional context

No response

Originally created by @juninaba on GitHub (Oct 2, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/5037 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Call ‎`auth.api.removeTeamMember`. 2. Observe the API response: 200 with ‎`{ message: 'Team member removed successfully.' }`. 3. The record still exists and has not been deleted. ### Current vs. Expected behavior Current: • ‎`auth.api.removeTeamMember` returns a success message and 200 status, but the team membership record remains in the database. Expected: • On success, the corresponding team membership record should be deleted from the database. ### What version of Better Auth are you using? v1.3.8 ### System info ```bash { "system": { "platform": "darwin", "arch": "arm64", "version": "Darwin Kernel Version 25.0.0: Mon Aug 25 21:17:54 PDT 2025; root:xnu-12377.1.9~3/RELEASE_ARM64_T6041", "release": "25.0.0", "cpuCount": 14, "cpuModel": "Apple M4 Pro", "totalMemory": "48.00 GB", "freeMemory": "2.07 GB" }, "node": { "version": "v24.7.0", "env": "development" }, "packageManager": { "name": "npm", "version": "11.5.1" }, "frameworks": null, "databases": null, "betterAuth": { "version": "Unknown", "config": null } } ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth" export const auth = betterAuth({ database: prismaAdapter(client, { provider: 'postgresql' }), emailAndPassword: { enabled: true, requireEmailVerification: true, sendResetPassword: async ({ user, url }) => { const { subject, text } = buildPasswordResetEmail(user.email, url); await sendEmail({ to: user.email, subject, text }); }, }, emailVerification: { sendOnSignUp: true, sendOnSignIn: true, autoSignInAfterVerification: true, sendVerificationEmail: async ({ user, url }) => { const { subject, text } = buildVerificationEmail(user.email, url); await sendEmail({ to: user.email, subject, text }); }, }, socialProviders: { google: { prompt: "select_account", clientId: process.env.GOOGLE_CLIENT_ID || '', clientSecret: process.env.GOOGLE_CLIENT_SECRET || '', } }, plugins: [ organization({ teams: { enabled: true }, requireEmailVerificationOnInvitation: true, async sendInvitationEmail(data) { const inviteLink = `/api/accept-invitation/${data.id}`; const { subject, text } = buildInvitationEmail(data.email, data.inviter.user.name, inviteLink); await sendEmail({ to: data.email, subject, text }); }, }), twoFactor(), ] }); ``` ### Additional context _No response_
GiteaMirror added the lockedbug labels 2026-04-13 06:05:48 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Oct 2, 2025):

Hi @juninaba! I'm Dosu and I’m helping the better-auth team.

This is a valid issue for GitHub. The intended behavior of auth.api.removeTeamMember is to delete the team membership record from the database by calling adapter.delete on the teamMember model with the specified teamId and userId. If you receive a success response but the record remains, it likely indicates a bug or a schema/configuration problem.

There is a known issue where a schema mismatch—specifically, team.id being an integer and teamMember.teamId being text—can silently break deletion operations, especially with PostgreSQL. This mismatch breaks referential integrity and can cause the delete operation to fail without error, resulting in the behavior you described. The workaround is to ensure that teamMember.teamId matches the type of team.id in your schema (both should be integer if team.id is serial) [source].

Recent pull requests confirm that the deletion logic is supposed to work as you expect, and there are no explicit error checks if the deletion fails—so a silent failure is possible if the schema is mismatched or the adapter is misconfigured [source].

Check your schema for type mismatches and update as needed. If your schema is correct and the issue persists, it may be a bug in v1.3.8 or a problem with your adapter configuration.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

<!-- gh-comment-id:3361036297 --> @dosubot[bot] commented on GitHub (Oct 2, 2025): <!-- Greeting --> Hi @juninaba! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> This is a valid issue for GitHub. The intended behavior of auth.api.removeTeamMember is to delete the team membership record from the database by calling adapter.delete on the teamMember model with the specified teamId and userId. If you receive a success response but the record remains, it likely indicates a bug or a schema/configuration problem. There is a known issue where a schema mismatch—specifically, team.id being an integer and teamMember.teamId being text—can silently break deletion operations, especially with PostgreSQL. This mismatch breaks referential integrity and can cause the delete operation to fail without error, resulting in the behavior you described. The workaround is to ensure that teamMember.teamId matches the type of team.id in your schema (both should be integer if team.id is serial) [[source]](https://github.com/better-auth/better-auth/issues/3800). Recent pull requests confirm that the deletion logic is supposed to work as you expect, and there are no explicit error checks if the deletion fails—so a silent failure is possible if the schema is mismatched or the adapter is misconfigured [[source]](https://github.com/better-auth/better-auth/pull/3446). Check your schema for type mismatches and update as needed. If your schema is correct and the issue persists, it may be a bug in v1.3.8 or a problem with your adapter configuration. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/add238f9-8d6e-4b6e-bf08-8abb667f5798?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/add238f9-8d6e-4b6e-bf08-8abb667f5798?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/add238f9-8d6e-4b6e-bf08-8abb667f5798?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/add238f9-8d6e-4b6e-bf08-8abb667f5798?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/add238f9-8d6e-4b6e-bf08-8abb667f5798?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/add238f9-8d6e-4b6e-bf08-8abb667f5798?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/add238f9-8d6e-4b6e-bf08-8abb667f5798?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/5037)
Author
Owner

@ping-maxwell commented on GitHub (Oct 3, 2025):

Can you send your actual auth config?

<!-- gh-comment-id:3364235192 --> @ping-maxwell commented on GitHub (Oct 3, 2025): Can you send your actual auth config?
Author
Owner

@juninaba commented on GitHub (Oct 3, 2025):

@ping-maxwell

Can you send your actual auth config?

I’ve updated the issue with my actual auth config.

<!-- gh-comment-id:3364269609 --> @juninaba commented on GitHub (Oct 3, 2025): @ping-maxwell > Can you send your actual auth config? I’ve updated the issue with my actual auth config.
Author
Owner

@juninaba commented on GitHub (Oct 3, 2025):

d3ff4da4f6/packages/better-auth/src/plugins/organization/adapter.ts (L819-L834)

The issue appears to be specific to the Prisma adapter. In Prisma, delete() only accepts a unique constraint field as a condition, while deleteMany() supports arbitrary conditions (AND/OR, multiple fields). This constraint may be causing the problem.

<!-- gh-comment-id:3364279662 --> @juninaba commented on GitHub (Oct 3, 2025): https://github.com/better-auth/better-auth/blob/d3ff4da4f600cd7ee8cc4051e899ab7c077f4483/packages/better-auth/src/plugins/organization/adapter.ts#L819-L834 The issue appears to be specific to the Prisma adapter. In Prisma, `delete()` only accepts a unique constraint field as a condition, while `deleteMany()` supports arbitrary conditions (AND/OR, multiple fields). This constraint may be causing the problem.
Author
Owner

@ping-maxwell commented on GitHub (Oct 3, 2025):

Yeah I think that's right.

<!-- gh-comment-id:3364363923 --> @ping-maxwell commented on GitHub (Oct 3, 2025): Yeah I think that's right.
Author
Owner

@aniketicloud commented on GitHub (Nov 5, 2025):

I still see the issue. I used server api to remove the member. I got success message but member was not removed.

<!-- gh-comment-id:3492968272 --> @aniketicloud commented on GitHub (Nov 5, 2025): I still see the issue. I used server api to remove the member. I got success message but member was not removed.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#10149