Unable to create plugin

I'm currently using admin plugin with phone plugin , i need a way to setup custom endpoints that enables admins to create users with a phoneNumber without otp and a role , i know it is going to be possible with custom plugin and i can directly tap into the db instance of better auth , but unfortunately , when i try to setup , there is a issue that i am encountering
Solution:
This did work once i made the function async
Jump to solution
2 Replies
Mohammed Anas
Mohammed AnasOP2mo ago
<-- GET /auth/custom/test
# SERVER_ERROR: TypeError: handler(...).catch is not a function
at internalHandler (/Users/anasmohammed361/vs/webzenith/mutual-space/mutual-funds-web/node_modules/.pnpm/better-call@1.0.16/node_modules/better-call/src/endpoint.ts:340:58)
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
at async api.<computed> (/Users/anasmohammed361/vs/webzenith/mutual-space/mutual-funds-web/node_modules/.pnpm/better-auth@1.3.7_react-dom@19.1.0_react@19.1.0__react@19.1.0_zod@4.0.5/node_modules/better-auth/dist/shared/better-auth.C-iQKHit.cjs:6211:22)
at async processRequest (/Users/anasmohammed361/vs/webzenith/mutual-space/mutual-funds-web/node_modules/.pnpm/better-call@1.0.16/node_modules/better-call/src/router.ts:193:22)
at async handler (/Users/anasmohammed361/vs/webzenith/mutual-space/mutual-funds-web/node_modules/.pnpm/better-call@1.0.16/node_modules/better-call/src/router.ts:214:16)
at async dispatch (/Users/anasmohammed361/vs/webzenith/mutual-space/mutual-funds-web/node_modules/.pnpm/hono@4.8.5/node_modules/hono/dist/cjs/compose.js:44:17)
at async dispatch (/Users/anasmohammed361/vs/webzenith/mutual-space/mutual-funds-web/node_modules/.pnpm/hono@4.8.5/node_modules/hono/dist/cjs/compose.js:44:17)
at async cors2 (/Users/anasmohammed361/vs/webzenith/mutual-space/mutual-funds-web/node_modules/.pnpm/hono@4.8.5/node_modules/hono/dist/cjs/middleware/cors/index.js:106:5)
at async dispatch (/Users/anasmohammed361/vs/webzenith/mutual-space/mutual-funds-web/node_modules/.pnpm/hono@4.8.5/node_modules/hono/dist/cjs/compose.js:44:17)
at async logger2 (/Users/anasmohammed361/vs/webzenith/mutual-space/mutual-funds-web/node_modules/.pnpm/hono@4.8.5/node_modules/hono/dist/cjs/middleware/logger/index.js:66:5)
--> GET /auth/custom/test 500 17ms
<-- GET /auth/custom/test
# SERVER_ERROR: TypeError: handler(...).catch is not a function
at internalHandler (/Users/anasmohammed361/vs/webzenith/mutual-space/mutual-funds-web/node_modules/.pnpm/better-call@1.0.16/node_modules/better-call/src/endpoint.ts:340:58)
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
at async api.<computed> (/Users/anasmohammed361/vs/webzenith/mutual-space/mutual-funds-web/node_modules/.pnpm/better-auth@1.3.7_react-dom@19.1.0_react@19.1.0__react@19.1.0_zod@4.0.5/node_modules/better-auth/dist/shared/better-auth.C-iQKHit.cjs:6211:22)
at async processRequest (/Users/anasmohammed361/vs/webzenith/mutual-space/mutual-funds-web/node_modules/.pnpm/better-call@1.0.16/node_modules/better-call/src/router.ts:193:22)
at async handler (/Users/anasmohammed361/vs/webzenith/mutual-space/mutual-funds-web/node_modules/.pnpm/better-call@1.0.16/node_modules/better-call/src/router.ts:214:16)
at async dispatch (/Users/anasmohammed361/vs/webzenith/mutual-space/mutual-funds-web/node_modules/.pnpm/hono@4.8.5/node_modules/hono/dist/cjs/compose.js:44:17)
at async dispatch (/Users/anasmohammed361/vs/webzenith/mutual-space/mutual-funds-web/node_modules/.pnpm/hono@4.8.5/node_modules/hono/dist/cjs/compose.js:44:17)
at async cors2 (/Users/anasmohammed361/vs/webzenith/mutual-space/mutual-funds-web/node_modules/.pnpm/hono@4.8.5/node_modules/hono/dist/cjs/middleware/cors/index.js:106:5)
at async dispatch (/Users/anasmohammed361/vs/webzenith/mutual-space/mutual-funds-web/node_modules/.pnpm/hono@4.8.5/node_modules/hono/dist/cjs/compose.js:44:17)
at async logger2 (/Users/anasmohammed361/vs/webzenith/mutual-space/mutual-funds-web/node_modules/.pnpm/hono@4.8.5/node_modules/hono/dist/cjs/middleware/logger/index.js:66:5)
--> GET /auth/custom/test 500 17ms
I have attached the logs for reference
import type { BetterAuthPlugin } from "better-auth";
import { createAuthEndpoint } from "better-auth/api";

export const adminCreateUserWithRole = ()=>{
return {
id: "custom-plugin",
endpoints:{
createUserWithRole:createAuthEndpoint("/custom/test", {
method: "GET",
},(ctx)=>{
// const {context} = ctx;
// console.log(context.session?.user);

return ctx.json({
message: "Logged"
})
})
}
} satisfies BetterAuthPlugin
}
import type { BetterAuthPlugin } from "better-auth";
import { createAuthEndpoint } from "better-auth/api";

export const adminCreateUserWithRole = ()=>{
return {
id: "custom-plugin",
endpoints:{
createUserWithRole:createAuthEndpoint("/custom/test", {
method: "GET",
},(ctx)=>{
// const {context} = ctx;
// console.log(context.session?.user);

return ctx.json({
message: "Logged"
})
})
}
} satisfies BetterAuthPlugin
}
This is my plugin code
import { betterAuth } from "better-auth";

// Database Adapter
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import * as schema from "@repo/drizzle/schema"
import { db } from "@repo/drizzle/index";

// Plugins
import { openAPI, phoneNumber, admin as adminPlugin } from "better-auth/plugins"

// Authorization
import { admin, advisor, user, ac } from "./permission"
import { adminCreateUserWithRole } from "./plugins/admin-create-user-with-role";

const auth = betterAuth({
appName: "Mutual Funds",
basePath: "/auth",
user:{
additionalFields:{
advisorType:{
type:'string',
required:false,
input:false,
}
}
},
database: drizzleAdapter(db, {
provider: 'pg',
schema
}),
plugins: [openAPI({
disableDefaultReference: false,
}),
phoneNumber({
sendOTP(data, request) {
console.log(data)
// TODO: Implement OTP sending
},
signUpOnVerification: {
getTempEmail(phoneNumber) {
return `temp-${phoneNumber}@temp.internal`
},
getTempName(phoneNumber) {
return `Temp ${phoneNumber}`
},
},
}),
adminPlugin({
ac,
roles: {
admin,
advisor,
user
},
adminRoles: ["admin"],
defaultRole: "user",
}),
adminCreateUserWithRole(),
],
});
type Auth = typeof auth;
export { auth, type Auth }
import { betterAuth } from "better-auth";

// Database Adapter
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import * as schema from "@repo/drizzle/schema"
import { db } from "@repo/drizzle/index";

// Plugins
import { openAPI, phoneNumber, admin as adminPlugin } from "better-auth/plugins"

// Authorization
import { admin, advisor, user, ac } from "./permission"
import { adminCreateUserWithRole } from "./plugins/admin-create-user-with-role";

const auth = betterAuth({
appName: "Mutual Funds",
basePath: "/auth",
user:{
additionalFields:{
advisorType:{
type:'string',
required:false,
input:false,
}
}
},
database: drizzleAdapter(db, {
provider: 'pg',
schema
}),
plugins: [openAPI({
disableDefaultReference: false,
}),
phoneNumber({
sendOTP(data, request) {
console.log(data)
// TODO: Implement OTP sending
},
signUpOnVerification: {
getTempEmail(phoneNumber) {
return `temp-${phoneNumber}@temp.internal`
},
getTempName(phoneNumber) {
return `Temp ${phoneNumber}`
},
},
}),
adminPlugin({
ac,
roles: {
admin,
advisor,
user
},
adminRoles: ["admin"],
defaultRole: "user",
}),
adminCreateUserWithRole(),
],
});
type Auth = typeof auth;
export { auth, type Auth }
and this is my server plugin Just for the context , i'm on mac and i use turborepo for my setup
Solution
Mohammed Anas
Mohammed Anas2mo ago
This did work once i made the function async

Did you find this page helpful?