[GH-ISSUE #6991] bug report for custom roles #28015

Closed
opened 2026-04-17 19:21:17 -05:00 by GiteaMirror · 13 comments
Owner

Originally created by @mamuk0 on GitHub (Dec 24, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/6991

Originally assigned to: @bytaesu on GitHub.

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Create permissions and roles in permission.ts. (Create another role besides "admin" or "user" so you can see the error.)
  2. Configure the necessary settings for auth.ts and auth-client.ts
  3. Enable emailAndPassword signup mode.
  4. You will encounter an error when attempting to create an account with the code example;
export async function createUserWithRole(data: {
    name: string;
    email: string;
    password: string;
    phone?: string;
    role: UserRole; // (The type values of the roles here come from the enums generated by the prisma orm.)
    accountStatus?: boolean;
}) {
    await checkAdminOnlyAccess();

    try {
        const result = await auth.api.createUser({
            headers: await headers(),
            body: {
                email: data.email,
                password: data.password,
                name: data.name,
                role: data.role,
                data: {
                    phone: data.phone || "",
                    accountStatus: data.accountStatus !== undefined ? data.accountStatus : true,
                },
            },
        });

        if (!result) {
            throw new Error("User can not be created");
        }

        return result;
    } catch (error) {
        throw new Error("Smth went wrong!");
    }
}

Current vs. Expected behavior

  1. Screenshot:
Image
  1. Screenshot:
Image

Normally, the role definition you see in the second image on line 191 should be inferred, meaning it should include custom role definitions in the project. However, in admin.d.mts, it is hardcoded only as “user” or “admin.” It does not use the inferred values.

There was no such issue when using the old version (better-auth@1.4.5), and the screenshot of the equivalent file (admin.d.mts) is as follows:

Image

While custom roles were previously inferred, they are now only used as “user” and “admin,” which causes errors in running applications.

What version of Better Auth are you using?

1.4.9

System info

{
  "system": {
    "platform": "linux",
    "arch": "x64",
    "version": "#37~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Thu Nov 20 10:25:38 UTC 2",
    "release": "6.14.0-37-generic",
    "cpuCount": 32,
    "cpuModel": "14th Gen Intel(R) Core(TM) i9-14900K",
    "totalMemory": "64.03 GB",
    "freeMemory": "54.08 GB"
  },
  "node": {
    "version": "v24.12.0",
    "env": "production"
  },
  "packageManager": {
    "name": "bun",
    "version": "1.3.5"
  },
  "frameworks": [
    {
      "name": "next",
      "version": "16.1.1"
    },
    {
      "name": "react",
      "version": "19.2.3"
    }
  ],
  "databases": [
    {
      "name": "@prisma/client",
      "version": "^6.19.0"
    }
  ],
  "betterAuth": {
    "version": "^1.4.9",
    "config": {
      "emailAndPassword": {
        "enabled": true
      },
      "socialProviders": {
        "google": {
          "clientId": "[REDACTED]",
          "clientSecret": "[REDACTED]"
        }
      },
      "user": {
        "additionalFields": {
          "phone": {
            "type": "string",
            "required": true,
            "input": true
          },
          "accountStatus": {
            "type": "boolean",
            "required": false,
            "defaultValue": true,
            "input": false
          }
        }
      },
      "plugins": [
        {
          "name": "admin",
          "config": {
            "id": "admin",
            "hooks": {
              "after": [
                {}
              ]
            },
            "endpoints": {},
            "$ERROR_CODES": {
              "FAILED_TO_CREATE_USER": "Failed to create user",
              "USER_ALREADY_EXISTS": "User already exists.",
              "USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL": "User already exists. Use another email.",
              "YOU_CANNOT_BAN_YOURSELF": "You cannot ban yourself",
              "YOU_ARE_NOT_ALLOWED_TO_CHANGE_USERS_ROLE": "You are not allowed to change users role",
              "YOU_ARE_NOT_ALLOWED_TO_CREATE_USERS": "You are not allowed to create users",
              "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS": "You are not allowed to list users",
              "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS_SESSIONS": "You are not allowed to list users sessions",
              "YOU_ARE_NOT_ALLOWED_TO_BAN_USERS": "You are not allowed to ban users",
              "YOU_ARE_NOT_ALLOWED_TO_IMPERSONATE_USERS": "You are not allowed to impersonate users",
              "YOU_ARE_NOT_ALLOWED_TO_REVOKE_USERS_SESSIONS": "You are not allowed to revoke users sessions",
              "YOU_ARE_NOT_ALLOWED_TO_DELETE_USERS": "You are not allowed to delete users",
              "YOU_ARE_NOT_ALLOWED_TO_SET_USERS_PASSWORD": "[REDACTED]",
              "BANNED_USER": "You have been banned from this application",
              "YOU_ARE_NOT_ALLOWED_TO_GET_USER": "You are not allowed to get user",
              "NO_DATA_TO_UPDATE": "No data to update",
              "YOU_ARE_NOT_ALLOWED_TO_UPDATE_USERS": "You are not allowed to update users",
              "YOU_CANNOT_REMOVE_YOURSELF": "You cannot remove yourself",
              "YOU_ARE_NOT_ALLOWED_TO_SET_NON_EXISTENT_VALUE": "You are not allowed to set a non-existent role value",
              "YOU_CANNOT_IMPERSONATE_ADMINS": "You cannot impersonate admins",
              "INVALID_ROLE_TYPE": "Invalid role type"
            },
            "schema": {
              "user": {
                "fields": {
                  "role": {
                    "type": "string",
                    "required": false,
                    "input": false
                  },
                  "banned": {
                    "type": "boolean",
                    "defaultValue": false,
                    "required": false,
                    "input": false
                  },
                  "banReason": {
                    "type": "string",
                    "required": false,
                    "input": false
                  },
                  "banExpires": {
                    "type": "date",
                    "required": false,
                    "input": false
                  }
                }
              },
              "session": {
                "fields": {
                  "impersonatedBy": {
                    "type": "string",
                    "required": false
                  }
                }
              }
            },
            "options": {
              "ac": {
                "statements": {
                  "user": [
                    "create",
                    "list",
                    "set-role",
                    "ban",
                    "impersonate",
                    "delete",
                    "set-password",
                    "get",
                    "update"
                  ],
                  "session": [
                    "list",
                    "revoke",
                    "delete"
                  ],
                  "lead": [
                    "create",
                    "read",
                    "update",
                    "delete",
                    "assign",
                    "import"
                  ]
                }
              },
              "roles": {
                "admin": {
                  "statements": {
                    "user": [
                      "create",
                      "list",
                      "set-role",
                      "ban",
                      "impersonate",
                      "delete",
                      "set-password",
                      "get",
                      "update"
                    ],
                    "session": [
                      "list",
                      "revoke",
                      "delete"
                    ],
                    "lead": [
                      "create",
                      "read",
                      "update",
                      "delete",
                      "assign",
                      "import"
                    ]
                  }
                },
                "moderator": {
                  "statements": {
                    "lead": [
                      "read",
                      "update"
                    ]
                  }
                },
                "user": {
                  "statements": {
                    "lead": [
                      "read"
                    ]
                  }
                }
              },
              "defaultRole": "user",
              "adminRoles": [
                "admin"
              ]
            }
          }
        },
        {
          "name": "haveIBeenPwned",
          "config": {
            "id": "haveIBeenPwned",
            "$ERROR_CODES": {
              "PASSWORD_COMPROMISED": "The password you entered has been compromised. Please choose a different password."
            }
          }
        },
        {
          "name": "next-cookies",
          "config": {
            "id": "next-cookies",
            "hooks": {
              "after": [
                {}
              ]
            }
          }
        },
        {
          "name": "better-auth-localization",
          "config": {
            "id": "better-auth-localization",
            "hooks": {
              "after": [
                {}
              ]
            }
          }
        }
      ]
    }
  }
}

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

Backend

Auth config (if applicable)

import { betterAuth } from "better-auth";
import { localization } from "better-auth-localization";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { nextCookies } from "better-auth/next-js";
import { admin, haveIBeenPwned } from "better-auth/plugins";
import { prisma } from "./db";
import { ac, adminRole, moderatorRole, userRole } from "./permissions";

export const auth = betterAuth({
    emailAndPassword: {
        enabled: true,
    },
    socialProviders: {
        google: {
            clientId: process.env.GOOGLE_CLIENT_ID as string,
            clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
        },
    },
    database: prismaAdapter(prisma, {
        provider: "postgresql",
    }),
    user: {
        additionalFields: {
            phone: {
                type: "string",
                required: true,
                input: true,
            },
            accountStatus: {
                type: "boolean",
                required: false,
                defaultValue: true,
                input: false,
            }
        }
    },
    plugins: [
        admin({
            ac,
            roles: {
                admin: adminRole,
                moderator: moderatorRole,
                user: userRole,
            },
            defaultRole: "user",
            adminRoles: ["admin"],
        }),
        haveIBeenPwned(),
        nextCookies(),
        localization({
            defaultLocale: "tr-TR",
            fallbackLocale: "default"
        })
    ],
});

Additional context

No response

Originally created by @mamuk0 on GitHub (Dec 24, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/6991 Originally assigned to: @bytaesu on GitHub. ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Create permissions and roles in permission.ts. (Create another role besides "admin" or "user" so you can see the error.) 2. Configure the necessary settings for auth.ts and auth-client.ts 3. Enable emailAndPassword signup mode. 4. You will encounter an error when attempting to create an account with the code example; ``` export async function createUserWithRole(data: { name: string; email: string; password: string; phone?: string; role: UserRole; // (The type values of the roles here come from the enums generated by the prisma orm.) accountStatus?: boolean; }) { await checkAdminOnlyAccess(); try { const result = await auth.api.createUser({ headers: await headers(), body: { email: data.email, password: data.password, name: data.name, role: data.role, data: { phone: data.phone || "", accountStatus: data.accountStatus !== undefined ? data.accountStatus : true, }, }, }); if (!result) { throw new Error("User can not be created"); } return result; } catch (error) { throw new Error("Smth went wrong!"); } } ``` ### Current vs. Expected behavior 1. Screenshot: <img width="1897" height="469" alt="Image" src="https://github.com/user-attachments/assets/b4a69f5a-35f8-4ef5-8dcb-8c67086f4009" /> 2. Screenshot: <img width="1953" height="867" alt="Image" src="https://github.com/user-attachments/assets/9eb74ab7-a55d-4f9f-be64-f6f1fb4e3575" /> Normally, the role definition you see in the second image on line 191 should be inferred, meaning it should include custom role definitions in the project. However, in admin.d.mts, it is hardcoded only as “user” or “admin.” It does not use the inferred values. There was no such issue when using the old version (better-auth@1.4.5), and the screenshot of the equivalent file (admin.d.mts) is as follows: <img width="1953" height="867" alt="Image" src="https://github.com/user-attachments/assets/d7ca3573-9efb-4cb9-a514-62efac606cf8" /> While custom roles were previously inferred, they are now only used as “user” and “admin,” which causes errors in running applications. ### What version of Better Auth are you using? 1.4.9 ### System info ```bash { "system": { "platform": "linux", "arch": "x64", "version": "#37~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Thu Nov 20 10:25:38 UTC 2", "release": "6.14.0-37-generic", "cpuCount": 32, "cpuModel": "14th Gen Intel(R) Core(TM) i9-14900K", "totalMemory": "64.03 GB", "freeMemory": "54.08 GB" }, "node": { "version": "v24.12.0", "env": "production" }, "packageManager": { "name": "bun", "version": "1.3.5" }, "frameworks": [ { "name": "next", "version": "16.1.1" }, { "name": "react", "version": "19.2.3" } ], "databases": [ { "name": "@prisma/client", "version": "^6.19.0" } ], "betterAuth": { "version": "^1.4.9", "config": { "emailAndPassword": { "enabled": true }, "socialProviders": { "google": { "clientId": "[REDACTED]", "clientSecret": "[REDACTED]" } }, "user": { "additionalFields": { "phone": { "type": "string", "required": true, "input": true }, "accountStatus": { "type": "boolean", "required": false, "defaultValue": true, "input": false } } }, "plugins": [ { "name": "admin", "config": { "id": "admin", "hooks": { "after": [ {} ] }, "endpoints": {}, "$ERROR_CODES": { "FAILED_TO_CREATE_USER": "Failed to create user", "USER_ALREADY_EXISTS": "User already exists.", "USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL": "User already exists. Use another email.", "YOU_CANNOT_BAN_YOURSELF": "You cannot ban yourself", "YOU_ARE_NOT_ALLOWED_TO_CHANGE_USERS_ROLE": "You are not allowed to change users role", "YOU_ARE_NOT_ALLOWED_TO_CREATE_USERS": "You are not allowed to create users", "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS": "You are not allowed to list users", "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS_SESSIONS": "You are not allowed to list users sessions", "YOU_ARE_NOT_ALLOWED_TO_BAN_USERS": "You are not allowed to ban users", "YOU_ARE_NOT_ALLOWED_TO_IMPERSONATE_USERS": "You are not allowed to impersonate users", "YOU_ARE_NOT_ALLOWED_TO_REVOKE_USERS_SESSIONS": "You are not allowed to revoke users sessions", "YOU_ARE_NOT_ALLOWED_TO_DELETE_USERS": "You are not allowed to delete users", "YOU_ARE_NOT_ALLOWED_TO_SET_USERS_PASSWORD": "[REDACTED]", "BANNED_USER": "You have been banned from this application", "YOU_ARE_NOT_ALLOWED_TO_GET_USER": "You are not allowed to get user", "NO_DATA_TO_UPDATE": "No data to update", "YOU_ARE_NOT_ALLOWED_TO_UPDATE_USERS": "You are not allowed to update users", "YOU_CANNOT_REMOVE_YOURSELF": "You cannot remove yourself", "YOU_ARE_NOT_ALLOWED_TO_SET_NON_EXISTENT_VALUE": "You are not allowed to set a non-existent role value", "YOU_CANNOT_IMPERSONATE_ADMINS": "You cannot impersonate admins", "INVALID_ROLE_TYPE": "Invalid role type" }, "schema": { "user": { "fields": { "role": { "type": "string", "required": false, "input": false }, "banned": { "type": "boolean", "defaultValue": false, "required": false, "input": false }, "banReason": { "type": "string", "required": false, "input": false }, "banExpires": { "type": "date", "required": false, "input": false } } }, "session": { "fields": { "impersonatedBy": { "type": "string", "required": false } } } }, "options": { "ac": { "statements": { "user": [ "create", "list", "set-role", "ban", "impersonate", "delete", "set-password", "get", "update" ], "session": [ "list", "revoke", "delete" ], "lead": [ "create", "read", "update", "delete", "assign", "import" ] } }, "roles": { "admin": { "statements": { "user": [ "create", "list", "set-role", "ban", "impersonate", "delete", "set-password", "get", "update" ], "session": [ "list", "revoke", "delete" ], "lead": [ "create", "read", "update", "delete", "assign", "import" ] } }, "moderator": { "statements": { "lead": [ "read", "update" ] } }, "user": { "statements": { "lead": [ "read" ] } } }, "defaultRole": "user", "adminRoles": [ "admin" ] } } }, { "name": "haveIBeenPwned", "config": { "id": "haveIBeenPwned", "$ERROR_CODES": { "PASSWORD_COMPROMISED": "The password you entered has been compromised. Please choose a different password." } } }, { "name": "next-cookies", "config": { "id": "next-cookies", "hooks": { "after": [ {} ] } } }, { "name": "better-auth-localization", "config": { "id": "better-auth-localization", "hooks": { "after": [ {} ] } } } ] } } } ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth"; import { localization } from "better-auth-localization"; import { prismaAdapter } from "better-auth/adapters/prisma"; import { nextCookies } from "better-auth/next-js"; import { admin, haveIBeenPwned } from "better-auth/plugins"; import { prisma } from "./db"; import { ac, adminRole, moderatorRole, userRole } from "./permissions"; export const auth = betterAuth({ emailAndPassword: { enabled: true, }, socialProviders: { google: { clientId: process.env.GOOGLE_CLIENT_ID as string, clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, }, }, database: prismaAdapter(prisma, { provider: "postgresql", }), user: { additionalFields: { phone: { type: "string", required: true, input: true, }, accountStatus: { type: "boolean", required: false, defaultValue: true, input: false, } } }, plugins: [ admin({ ac, roles: { admin: adminRole, moderator: moderatorRole, user: userRole, }, defaultRole: "user", adminRoles: ["admin"], }), haveIBeenPwned(), nextCookies(), localization({ defaultLocale: "tr-TR", fallbackLocale: "default" }) ], }); ``` ### Additional context _No response_
GiteaMirror added the lockedbug labels 2026-04-17 19:21:18 -05:00
Author
Owner

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

It sounds like you're encountering an issue with custom roles in Better Auth, specifically with the system not inferring these roles correctly. From your description, it seems that while the "admin" and "user" roles are recognized, custom roles aren't being accepted correctly due to hardcoded values in admin.d.mts in version 1.4.9, leading to errors during user creation.

To troubleshoot this, you might start by checking the following:

  1. Verify Role Configurations: Ensure that your role definitions in the code are correct and that you are using custom role values that are defined in your application.

  2. Review the Migration Path: Since you mentioned this worked in a previous version (1.4.5), it could be helpful to review any changes made to the roles between these versions to identify what might have led to this alteration.

  3. Testing Default Behavior: Try creating a user with the default roles to confirm whether the issue is isolated to custom roles.

If the issue persists and you cannot resolve it, I recommend tagging Beka (@bekacru) or Max (@ping__) directly here in GitHub. They would be able to provide more specific insights based on the current state and known issues with Better Auth.

Do you have any other configurations or modifications done in the project that might help in debugging this further?

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

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3690341567 --> @better-auth-agent[bot] commented on GitHub (Dec 24, 2025): It sounds like you're encountering an issue with custom roles in Better Auth, specifically with the system not inferring these roles correctly. From your description, it seems that while the "admin" and "user" roles are recognized, custom roles aren't being accepted correctly due to hardcoded values in `admin.d.mts` in version 1.4.9, leading to errors during user creation. To troubleshoot this, you might start by checking the following: 1. **Verify Role Configurations**: Ensure that your role definitions in the code are correct and that you are using custom role values that are defined in your application. 2. **Review the Migration Path**: Since you mentioned this worked in a previous version (1.4.5), it could be helpful to review any changes made to the roles between these versions to identify what might have led to this alteration. 3. **Testing Default Behavior**: Try creating a user with the default roles to confirm whether the issue is isolated to custom roles. If the issue persists and you cannot resolve it, I recommend tagging Beka (@bekacru) or Max (@ping__) directly here in GitHub. They would be able to provide more specific insights based on the current state and known issues with Better Auth. Do you have any other configurations or modifications done in the project that might help in debugging this further? _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

@dosubot[bot] commented on GitHub (Dec 24, 2025):

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

This is a known regression in Better Auth since v1.4.6: custom roles are no longer inferred in the admin plugin's API types, so TypeScript only accepts "user" and "admin" for the role field in endpoints like createUser and setRole. This happens because the type helper InferAdminRolesFromOption falls back to "user" | "admin" unless your roles config is captured as literal types at compile time. In v1.4.5 and earlier, the generic signature preserved custom role keys, so this bug did not occur [source].

Workarounds:

  • Use an explicit type assertion when passing your roles config to the admin plugin or client, e.g.:
    adminClient({
      ac,
      roles: { admin, user, moderator },
    } as Parameters<typeof adminClient>[0]);
    
  • Explicitly type your exported auth object using the satisfies keyword and ReturnType<typeof betterAuth>:
    const authConfig = { /* ... */ } satisfies BetterAuthOptions;
    export const auth = betterAuth(authConfig) as ReturnType<typeof betterAuth<typeof authConfig>>;
    
  • Use authClient.admin.createUser instead of auth.api.createUser for user creation, as this is the recommended method and may avoid some type errors [source].
  • As a last resort, relax strict TypeScript options in your tsconfig.json (e.g., set strict: false), but this reduces type safety [source].

Limitations:
These workarounds may reduce type safety or require manual updates if your roles change. The underlying issue is that the admin plugin's type inference does not always pick up custom roles unless the roles object is a literal at compile time [source].

If you need an immediate fix and can accept the risk, downgrading to v1.4.5 restores correct custom role inference. Otherwise, monitor for updates or PRs that address this type inference pipeline.

For more details and ongoing discussion, see issue #6642 and related code.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:3690346537 --> @dosubot[bot] commented on GitHub (Dec 24, 2025): <!-- Greeting --> Hi @mamuk0! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> This is a known regression in Better Auth since v1.4.6: custom roles are no longer inferred in the admin plugin's API types, so TypeScript only accepts "user" and "admin" for the `role` field in endpoints like `createUser` and `setRole`. This happens because the type helper `InferAdminRolesFromOption` falls back to `"user" | "admin"` unless your roles config is captured as literal types at compile time. In v1.4.5 and earlier, the generic signature preserved custom role keys, so this bug did not occur [[source](https://github.com/better-auth/better-auth/issues/6642)]. **Workarounds:** - Use an explicit type assertion when passing your roles config to the admin plugin or client, e.g.: ```ts adminClient({ ac, roles: { admin, user, moderator }, } as Parameters<typeof adminClient>[0]); ``` - Explicitly type your exported `auth` object using the `satisfies` keyword and `ReturnType<typeof betterAuth>`: ```ts const authConfig = { /* ... */ } satisfies BetterAuthOptions; export const auth = betterAuth(authConfig) as ReturnType<typeof betterAuth<typeof authConfig>>; ``` - Use `authClient.admin.createUser` instead of `auth.api.createUser` for user creation, as this is the recommended method and may avoid some type errors [[source](https://github.com/better-auth/better-auth/issues/3015)]. - As a last resort, relax strict TypeScript options in your `tsconfig.json` (e.g., set `strict: false`), but this reduces type safety [[source](https://github.com/better-auth/better-auth/issues/5047)]. **Limitations:** These workarounds may reduce type safety or require manual updates if your roles change. The underlying issue is that the admin plugin's type inference does not always pick up custom roles unless the roles object is a literal at compile time [[source](https://github.com/better-auth/better-auth/blob/35fcd1aa89b6e9978d7b34ec971066d6a8f1e4e3/packages/better-auth/src/plugins/admin/types.ts#L16-L91)]. **If you need an immediate fix and can accept the risk, downgrading to v1.4.5 restores correct custom role inference.** Otherwise, monitor for updates or PRs that address this type inference pipeline. For more details and ongoing discussion, see [issue #6642](https://github.com/better-auth/better-auth/issues/6642) and [related code](https://github.com/better-auth/better-auth/blob/35fcd1aa89b6e9978d7b34ec971066d6a8f1e4e3/packages/better-auth/src/plugins/admin/types.ts#L16-L91). <!-- 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/a1978cc2-3127-4f04-85f9-72ff31b9771e?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/a1978cc2-3127-4f04-85f9-72ff31b9771e?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/a1978cc2-3127-4f04-85f9-72ff31b9771e?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/a1978cc2-3127-4f04-85f9-72ff31b9771e?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/a1978cc2-3127-4f04-85f9-72ff31b9771e?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/a1978cc2-3127-4f04-85f9-72ff31b9771e?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/a1978cc2-3127-4f04-85f9-72ff31b9771e?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=This%20is%20a%20known%20regression%20in%20Better%20Auth%20since%20v1.4.6%3A%20custom%20roles%20are%20no%20longer%20inferred%20in%20the%20admin%20plugin%27s%20API%20types%2C%20so%20TypeScript%20only%20accepts%20%22user%22%20and%20%22admin%22%20for%20the%20%60role%60%20field%20in%20endpoints%20like%20%60createUser%60%20and%20%60setRole%60.%20This%20happens%20because%20the%20type%20helper%20%60InferAdminRolesFromOption%60%20falls%20back%20to%20%60%22user%22%20%7C%20%22admin%22%60%20unless%20your%20roles%20config%20is%20captured%20as%20literal%20types%20at%20compile%20time.%20In%20v1.4.5%20and%20earlier%2C%20the%20generic%20signature%20preserved%20custom%20role%20keys%2C%20so%20this%20bug%20did%20not%20occur%20%5B%5Bsource%5D%28https%3A//github.com/better-auth/better-auth/issues/6642%29%5D.%0A%0A%2A%2AWorkarounds%3A%2A%2A%0A-%20Use%20an%20explicit%20type%20assertion%20when%20passing%20your%20roles%20config%20to%20the%20admin%20plugin%20or%20client%2C%20e.g.%3A%0A%20%20%60%60%60ts%0A%20%20adminClient%28%7B%0A%20%20%20%20ac%2C%0A%20%20%20%20roles%3A%20%7B%20admin%2C%20user%2C%20moderator%20%7D%2C%0A%20%20%7D%20as%20Parameters%3Ctypeof%20adminClient%3E%5B0%5D%29%3B%0A%20%20%60%60%60%0A-%20Explicitly%20type%20your%20exported%20%60auth%60%20object%20using%20the%20%60satisfies%60%20keyword%20and%20%60ReturnType%3Ctypeof%20betterAuth%3E%60%3A%0A%20%20%60%60%60ts%0A%20%20const%20authConfig%20%3D%20%7B%20/%2A%20...%20%2A/%20%7D%20satisfies%20BetterAuthOptions%3B%0A%20%20export%20const%20auth%20%3D%20betterAuth%28authConfig%29%20as%20ReturnType%3Ctypeof%20betterAuth%3Ctypeof%20authConfig%3E%3E%3B%0A%20%20%60%60%60%0A-%20Use%20%60authClient.admin.createUser%60%20instead%20of%20%60auth.api.createUser%60%20for%20user%20creation%2C%20as%20this%20is%20the%20recommended%20method%20and%20may%20avoid%20some%20type%20errors%20%5B%5Bsource%5D%28https%3A//github.com/better-auth/better-auth/issues/3015%29%5D.%0A-%20As%20a%20last%20resort%2C%20relax%20strict%20TypeScript%20options%20in%20your%20%60tsconfig.json%60%20%28e.g.%2C%20set%20%60strict%3A%20false%60%29%2C%20but%20this%20reduces%20type%20safety%20%5B%5Bsource%5D%28https%3A//github.com/better-auth/better-auth/issues/5047%29%5D.%0A%0A%2A%2ALimitations%3A%2A%2A%20%20%0AThese%20workarounds%20may%20reduce%20type%20safety%20or%20require%20manual%20updates%20if%20your%20roles%20change.%20The%20underlying%20issue%20is%20that%20the%20admin%20plugin%27s%20type%20inference%20does%20not%20always%20pick%20up%20custom%20roles%20unless%20the%20roles%20object%20is%20a%20literal%20at%20compile%20time%20%5B%5Bsource%5D%28https%3A//github.com/better-auth/better-auth/blob/35fcd1aa89b6e9978d7b34ec971066d6a8f1e4e3/packages/better-auth/src/plugins/admin/types.ts%23L16-L91%29%5D.%0A%0A%2A%2AIf%20you%20need%20an%20immediate%20fix%20and%20can%20accept%20the%20risk%2C%20downgrading%20to%20v1.4.5%20restores%20correct%20custom%20role%20inference.%2A%2A%20Otherwise%2C%20monitor%20for%20updates%20or%20PRs%20that%20address%20this%20type%20inference%20pipeline.%0A%0AFor%20more%20details%20and%20ongoing%20discussion%2C%20see%20%5Bissue%20%236642%5D%28https%3A//github.com/better-auth/better-auth/issues/6642%29%20and%20%5Brelated%20code%5D%28https%3A//github.com/better-auth/better-auth/blob/35fcd1aa89b6e9978d7b34ec971066d6a8f1e4e3/packages/better-auth/src/plugins/admin/types.ts%23L16-L91%29.)&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/6991)
Author
Owner

@mamuk0 commented on GitHub (Dec 24, 2025):

@ping-maxwell @Bekacru

I didn't fully understand Dosu's suggestions. Because I may need to create roles and users, and the better-auth libraries only accept “admin” or "user" roles. What happens when I want to create a “moderator”? Does that mean I won't be able to do it after better-auth@1.4.6? Could you please suggest a cleaner and more understandable solution? I will update my code and run my tests accordingly. Thank you for your attention.

<!-- gh-comment-id:3690374208 --> @mamuk0 commented on GitHub (Dec 24, 2025): @ping-maxwell @Bekacru I didn't fully understand Dosu's suggestions. Because I may need to create roles and users, and the better-auth libraries only accept “admin” or "user" roles. What happens when I want to create a “moderator”? Does that mean I won't be able to do it after better-auth@1.4.6? Could you please suggest a cleaner and more understandable solution? I will update my code and run my tests accordingly. Thank you for your attention.
Author
Owner

@mamuk0 commented on GitHub (Dec 24, 2025):

@bytaesu If you have the opportunity, you may want to review this. Thank you for your interest.

<!-- gh-comment-id:3690380457 --> @mamuk0 commented on GitHub (Dec 24, 2025): @bytaesu If you have the opportunity, you may want to review this. Thank you for your interest.
Author
Owner

@bytaesu commented on GitHub (Dec 24, 2025):

@bytaesu If you have the opportunity, you may want to review this. Thank you for your interest.

Sure 😁

<!-- gh-comment-id:3690382626 --> @bytaesu commented on GitHub (Dec 24, 2025): > @bytaesu If you have the opportunity, you may want to review this. Thank you for your interest. Sure 😁
Author
Owner

@mamuk0 commented on GitHub (Dec 24, 2025):

@bytaesu If you have the opportunity, you may want to review this. Thank you for your interest.

Sure 😁

Thank you very much for your prompt response and interest. Actually, I'm wondering if this indicates that my code needs to be updated after version 1.4.5, or if it's a bug in better-auth. Because this error exists in newer versions, 1.4.6 and above.

<!-- gh-comment-id:3690412674 --> @mamuk0 commented on GitHub (Dec 24, 2025): > > [@bytaesu](https://github.com/bytaesu) If you have the opportunity, you may want to review this. Thank you for your interest. > > Sure 😁 Thank you very much for your prompt response and interest. Actually, I'm wondering if this indicates that my code needs to be updated after version 1.4.5, or if it's a bug in better-auth. Because this error exists in newer versions, 1.4.6 and above.
Author
Owner

@zkulbeda commented on GitHub (Dec 25, 2025):

Hi there! I faced with the same issue, seems typescript types are corrupted in published packages. I have no idea how this line of code in admin plugin:
4e63c40da9/packages/better-auth/src/plugins/admin/routes.ts (L308-L318)
transformed into this in better-auth/dist/plugins/admin/admin.d.mts declaration file from mode_modules

$Infer: {
  body: {
    email: string;
    password: string;
    name: string;
    role?: "user" | "admin" | ("user" | "admin")[] | undefined;
    data?: Record<string, any> | undefined;
  };
};
<!-- gh-comment-id:3691320880 --> @zkulbeda commented on GitHub (Dec 25, 2025): Hi there! I faced with the same issue, seems typescript types are corrupted in published packages. I have no idea how this line of code in `admin` plugin: https://github.com/better-auth/better-auth/blob/4e63c40da9139fe5425c3d9b40939522e6cfe2e8/packages/better-auth/src/plugins/admin/routes.ts#L308-L318 transformed into this in `better-auth/dist/plugins/admin/admin.d.mts` declaration file from mode_modules ```ts $Infer: { body: { email: string; password: string; name: string; role?: "user" | "admin" | ("user" | "admin")[] | undefined; data?: Record<string, any> | undefined; }; }; ```
Author
Owner

@mamuk0 commented on GitHub (Dec 25, 2025):

Hi there! I faced with the same issue, seems typescript types are corrupted in published packages. I have no idea how this line of code in admin plugin:

better-auth/packages/better-auth/src/plugins/admin/routes.ts

Lines 308 to 318 in 4e63c40

$Infer: {
body: {} as {
email: string;
password: string;
name: string;
role?:
| (InferAdminRolesFromOption | InferAdminRolesFromOption[])
| undefined;
data?: Record<string, any> | undefined;
},
},

transformed into this in better-auth/dist/plugins/admin/admin.d.mts declaration file from mode_modules
$Infer: {
body: {
email: string;
password: string;
name: string;
role?: "user" | "admin" | ("user" | "admin")[] | undefined;
data?: Record<string, any> | undefined;
};
};

I'm talking about exactly the same thing. I wonder if the use of custom roles has changed, or if they are no longer supported. Interesting. I'm just waiting.

<!-- gh-comment-id:3691391065 --> @mamuk0 commented on GitHub (Dec 25, 2025): > Hi there! I faced with the same issue, seems typescript types are corrupted in published packages. I have no idea how this line of code in `admin` plugin: > > [better-auth/packages/better-auth/src/plugins/admin/routes.ts](https://github.com/better-auth/better-auth/blob/4e63c40da9139fe5425c3d9b40939522e6cfe2e8/packages/better-auth/src/plugins/admin/routes.ts#L308-L318) > > Lines 308 to 318 in [4e63c40](/better-auth/better-auth/commit/4e63c40da9139fe5425c3d9b40939522e6cfe2e8) > > $Infer: { > body: {} as { > email: string; > password: string; > name: string; > role?: > | (InferAdminRolesFromOption<O> | InferAdminRolesFromOption<O>[]) > | undefined; > data?: Record<string, any> | undefined; > }, > }, > > transformed into this in `better-auth/dist/plugins/admin/admin.d.mts` declaration file from mode_modules > $Infer: { > body: { > email: string; > password: string; > name: string; > role?: "user" | "admin" | ("user" | "admin")[] | undefined; > data?: Record<string, any> | undefined; > }; > }; I'm talking about exactly the same thing. I wonder if the use of custom roles has changed, or if they are no longer supported. Interesting. I'm just waiting.
Author
Owner

@bytaesu commented on GitHub (Dec 25, 2025):

Hi @mamuk0 @zkulbeda 🙂

Could you try this version and let me know if this fixes the problem?

npm i https://pkg.pr.new/better-auth/better-auth@e9d54fa
<!-- gh-comment-id:3691618315 --> @bytaesu commented on GitHub (Dec 25, 2025): Hi @mamuk0 @zkulbeda 🙂 Could you try this version and let me know if this fixes the problem? ```sh npm i https://pkg.pr.new/better-auth/better-auth@e9d54fa ```
Author
Owner

@mamuk0 commented on GitHub (Dec 25, 2025):

Hi @mamuk0 @zkulbeda 🙂

Could you try this version and let me know if this fixes the problem?

npm i https://pkg.pr.new/better-auth/better-auth@e9d54fa

No, it doesn't work in the version you mentioned either. The reason for the error is this:

Property 'createUser' does not exist on type 'InferAPI<{ readonly ok: StrictEndpoint<"/ok", { method: "GET"; metadata: { openapi: { description: string; responses: { "200": { description: string; content: { "application/json": { schema: { type: "object"; properties: { ok: { type: string; description: string; }; }; required: string[]; }; }; }; }; }; }; scope: "s...'.ts(2339)

Image

Additionally, the adminClient() and admin() parameters (I'm referring to those in auth.ts and auth-client.ts for the plugin) are corrupted.

Image Image

We also thank you very much for your efforts and support!

<!-- gh-comment-id:3691633229 --> @mamuk0 commented on GitHub (Dec 25, 2025): > Hi [@mamuk0](https://github.com/mamuk0) [@zkulbeda](https://github.com/zkulbeda) 🙂 > > Could you try this version and let me know if this fixes the problem? > > npm i https://pkg.pr.new/better-auth/better-auth@e9d54fa No, it doesn't work in the version you mentioned either. The reason for the error is this: `Property 'createUser' does not exist on type 'InferAPI<{ readonly ok: StrictEndpoint<"/ok", { method: "GET"; metadata: { openapi: { description: string; responses: { "200": { description: string; content: { "application/json": { schema: { type: "object"; properties: { ok: { type: string; description: string; }; }; required: string[]; }; }; }; }; }; }; scope: "s...'.ts(2339) ` <img width="1831" height="371" alt="Image" src="https://github.com/user-attachments/assets/c106cec9-07fb-4fe7-bde8-c67245c5da2c" /> Additionally, the adminClient() and admin() parameters (I'm referring to those in auth.ts and auth-client.ts for the plugin) are corrupted. <img width="1918" height="896" alt="Image" src="https://github.com/user-attachments/assets/e9b90052-5ef4-4d0a-9aa4-f1b6f32e8e4f" /> <img width="1918" height="896" alt="Image" src="https://github.com/user-attachments/assets/99aba557-9859-42f8-a29e-6369e3fa8429" /> **We also thank you very much for your efforts and support!**
Author
Owner

@bytaesu commented on GitHub (Dec 25, 2025):

Hi @mamuk0,

I was able to reproduce the issue you reported in our Next.js demo app using v1.4.9, and I’ve confirmed that it's resolved with the changes I did 🤔

Let me know if there’s anything specific you’d like me to help with!


Before

Image

After

Image
<!-- gh-comment-id:3691650721 --> @bytaesu commented on GitHub (Dec 25, 2025): Hi @mamuk0, I was able to reproduce the issue you reported in our Next.js demo app using `v1.4.9`, and I’ve confirmed that it's resolved with the changes I did 🤔 Let me know if there’s anything specific you’d like me to help with! --- ### Before <img width="850" height="484" alt="Image" src="https://github.com/user-attachments/assets/310f36a2-32d5-4a24-b9c1-70028969fd13" /> ### After <img width="778" height="505" alt="Image" src="https://github.com/user-attachments/assets/81f65f4b-803b-4cee-87f8-2bc21b83e48b" />
Author
Owner

@mamuk0 commented on GitHub (Dec 25, 2025):

Hi @mamuk0,

I was able to reproduce the issue you reported in our Next.js demo app using v1.4.9, and I’ve confirmed that it's resolved with the changes I did 🤔

Let me know if there’s anything specific you’d like me to help with!

Before

Image ### After Image

Yes, I think there were some issues due to file caches and similar things, and it still looked faulty. Now the version you patched is working and there don't seem to be any problems. I also ran the typescript compiler, no issues there.

Do you have any idea how long it will take for better-auth to release it as a major version? Thank you very much again for your efforts and interest. Good night.

<!-- gh-comment-id:3691676486 --> @mamuk0 commented on GitHub (Dec 25, 2025): > Hi [@mamuk0](https://github.com/mamuk0), > > I was able to reproduce the issue you reported in our Next.js demo app using `v1.4.9`, and I’ve confirmed that it's resolved with the changes I did 🤔 > > Let me know if there’s anything specific you’d like me to help with! > > ### Before > <img alt="Image" width="850" height="484" src="https://private-user-images.githubusercontent.com/166604494/530228294-310f36a2-32d5-4a24-b9c1-70028969fd13.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NjY2ODkyNTAsIm5iZiI6MTc2NjY4ODk1MCwicGF0aCI6Ii8xNjY2MDQ0OTQvNTMwMjI4Mjk0LTMxMGYzNmEyLTMyZDUtNGEyNC1iOWMxLTcwMDI4OTY5ZmQxMy5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjUxMjI1JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI1MTIyNVQxODU1NTBaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT1iYTMyZGIwNTc0YzBhODMyYTY4NjNmYWM4MzRhMWJjNDhlODQ2MWQyMDExM2NmMjA0NGIxOWJmNzFjOTlmMTZkJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.fBD4iFUhSV78aCnV4pNTr5_Nz8R7p41PEGnqQzT-Vrc"> > ### After > <img alt="Image" width="778" height="505" src="https://private-user-images.githubusercontent.com/166604494/530228299-81f65f4b-803b-4cee-87f8-2bc21b83e48b.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NjY2ODkyNTAsIm5iZiI6MTc2NjY4ODk1MCwicGF0aCI6Ii8xNjY2MDQ0OTQvNTMwMjI4Mjk5LTgxZjY1ZjRiLTgwM2ItNGNlZS04N2Y4LTJiYzIxYjgzZTQ4Yi5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjUxMjI1JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI1MTIyNVQxODU1NTBaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT1kMWU2YjNmZmZmMDU3ZDhiYzc4NjVlNDc0ZDU4NGEzY2E1M2EwNDJiZmVkZjdkN2FkMDAzZDJmNDFkYWY0NWNhJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.qzupGQe8yh2cyDekMbb9H1k4k2vBYc10Wd5Fac99W0Q"> Yes, I think there were some issues due to file caches and similar things, and it still looked faulty. Now the version you patched is working and there don't seem to be any problems. I also ran the typescript compiler, no issues there. Do you have any idea how long it will take for better-auth to release it as a major version? Thank you very much again for your efforts and interest. Good night.
Author
Owner

@bytaesu commented on GitHub (Dec 25, 2025):

Our release cycle isn't very long, so it should be fairly soon 🙂

<!-- gh-comment-id:3691677964 --> @bytaesu commented on GitHub (Dec 25, 2025): Our release cycle isn't very long, so it should be fairly soon 🙂
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#28015