Error when using phoneNumber plugin. TypeError: segment.replace is not a function #1085

Closed
opened 2026-03-13 08:21:48 -05:00 by GiteaMirror · 4 comments
Owner

Originally created by @MAST1999 on GitHub (Apr 20, 2025).

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Use the ts-router template with solid prefix using this command bun create tsrouter-app --framework solid
  2. Create client and server auth
  3. Pass the client to the router context in the router.tsx file and define the type for it in the root like below.

router.tsx:

import { authClient } from "./lib/auth-client";
import {
	createRouter as createTanstackRouter,
	ErrorComponent,
} from "@tanstack/solid-router";

// Import the generated route tree
import { routeTree } from "./routeTree.gen";

// Create a new router instance
export const createRouter = () => {
	const router = createTanstackRouter({
		routeTree,
		scrollRestoration: true,
		context: {
			authClient,
		},
		defaultPendingComponent: () => <div class={`p-2 text-2xl`}>Loading...</div>,
		defaultErrorComponent: ({ error }) => <ErrorComponent error={error} />,
	});
	return router;
};

__root.tsx:

import type { authClient } from "~/lib/auth-client";

export const Route = createRootRouteWithContext<{
	authClient: typeof authClient;
}>()({
	component: RootComponent,
});
  1. Try to send a phone otp after access the auth client from the router context.
  2. See the error in the console.

I think it's becuase the Tanstack Router Solid is using Solid stores to keep the context and then the store goes through the proxy once and adds Symbol(store-raw) to the path.

Image

If I don't put the auth client in the router context and use it directly it works.

Current vs. Expected behavior

Sending OTP fails because of an error.

What version of Better Auth are you using?

1.2.7

Provide environment information

- OS: Arch Linux
- Browser: Chrome

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

Client

Auth config (if applicable)

export const auth = betterAuth({
	database: drizzleAdapter(db, { provider: "pg" }),
	emailAndPassword: {
		enabled: false,
	},
	plugins: [
		phoneNumber(),
	],
});

Additional context

No response

Originally created by @MAST1999 on GitHub (Apr 20, 2025). ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Use the ts-router template with solid prefix using this command `bun create tsrouter-app --framework solid` 2. Create client and server auth 3. Pass the client to the router context in the `router.tsx` file and define the type for it in the root like below. `router.tsx`: ```tsx import { authClient } from "./lib/auth-client"; import { createRouter as createTanstackRouter, ErrorComponent, } from "@tanstack/solid-router"; // Import the generated route tree import { routeTree } from "./routeTree.gen"; // Create a new router instance export const createRouter = () => { const router = createTanstackRouter({ routeTree, scrollRestoration: true, context: { authClient, }, defaultPendingComponent: () => <div class={`p-2 text-2xl`}>Loading...</div>, defaultErrorComponent: ({ error }) => <ErrorComponent error={error} />, }); return router; }; ``` `__root.tsx`: ```tsx import type { authClient } from "~/lib/auth-client"; export const Route = createRootRouteWithContext<{ authClient: typeof authClient; }>()({ component: RootComponent, }); ``` 4. Try to send a phone otp after access the auth client from the router context. 5. See the error in the console. I think it's becuase the Tanstack Router Solid is using Solid stores to keep the context and then the store goes through the proxy once and adds `Symbol(store-raw)` to the path. ![Image](https://github.com/user-attachments/assets/7ca7f856-2406-4f08-92b3-34348e98743f) If I don't put the auth client in the router context and use it directly it works. ### Current vs. Expected behavior Sending OTP fails because of an error. ### What version of Better Auth are you using? 1.2.7 ### Provide environment information ```bash - OS: Arch Linux - Browser: Chrome ``` ### Which area(s) are affected? (Select all that apply) Client ### Auth config (if applicable) ```typescript export const auth = betterAuth({ database: drizzleAdapter(db, { provider: "pg" }), emailAndPassword: { enabled: false, }, plugins: [ phoneNumber(), ], }); ``` ### Additional context _No response_
GiteaMirror added the solidbug labels 2026-03-13 08:21:48 -05:00
Author
Owner

@Bekacru commented on GitHub (Apr 22, 2025):

The client heavily relies on proxies to be able to construct the endpoint path, methods and so on. When you pass it through a context it'll easily lose it's reference. So I'd recommend you should just use it directly

@Bekacru commented on GitHub (Apr 22, 2025): The client heavily relies on proxies to be able to construct the endpoint path, methods and so on. When you pass it through a context it'll easily lose it's reference. So I'd recommend you should just use it directly
Author
Owner

@gossi commented on GitHub (Nov 4, 2025):

I have a case for re-opening this. Basically using better-auth from Ember 🥳

And I saw a very strange behavior, that this issue explained.

At first my authClient config:

// #/auth
import { createAuthClient } from 'better-auth/client';

export const auth = createAuthClient({
  baseURL: 'http://localhost:3000'
});

And then this snippet, which DOES NOT work:

import { auth } from '#/auth';

<template>
  <Button @push={{auth.revokeOtherSessions}}>
    Revoke other sessions
  </Button>
</template>

And here it does work:

import { auth } from '#/auth';

const revokeOtherSessions = auth.revokeOtherSessions;

<template>
  <Button @push={{revokeOtherSessions}}>
    Revoke other sessions
  </Button>
</template>

well, this issue explains why assigning it to a variable makes the code work. But the fact it is necessary is leading towards the issue it comes with. It puts pressure onto end-users thinking about the implementation details about the functions they are provided with (for which they should not have internal knowledga about), but carefully craft a situation where this is safe to be used in.

If so proxies are used - cool, then also ensure this is a safe-to-use API in whichever way end-users do use them.

PS. Even though I'm quite skilled with Ember, I don't know under which environment the better-auth functions are executed, that's only a couple of people working on Ember's core.

@gossi commented on GitHub (Nov 4, 2025): I have a case for re-opening this. Basically using better-auth from Ember 🥳 And I saw a very strange behavior, that this issue explained. At first my `authClient` config: ```ts // #/auth import { createAuthClient } from 'better-auth/client'; export const auth = createAuthClient({ baseURL: 'http://localhost:3000' }); ``` And then this snippet, which DOES NOT work: ```glimmer-ts import { auth } from '#/auth'; <template> <Button @push={{auth.revokeOtherSessions}}> Revoke other sessions </Button> </template> ``` And here it does work: ```glimmer-ts import { auth } from '#/auth'; const revokeOtherSessions = auth.revokeOtherSessions; <template> <Button @push={{revokeOtherSessions}}> Revoke other sessions </Button> </template> ``` well, this issue explains why assigning it to a variable makes the code work. But the fact it is necessary is leading towards the issue it comes with. It puts pressure onto end-users thinking about the implementation details about the functions they are provided with (for which they should not have internal knowledga about), but carefully craft a situation where this is safe to be used in. If so proxies are used - cool, then also ensure this is a safe-to-use API in whichever way end-users do use them. PS. Even though I'm quite skilled with Ember, I don't know under which environment the better-auth functions are executed, that's only a couple of people working on Ember's core.
Author
Owner

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

Hi there, thanks for reporting this issue! It looks like the error occurs because when the authClient is placed into the Tanstack Router Solid context, the Solid store proxy interferes with the methods on authClient—specifically causing the phoneNumber plugin’s OTP function to receive an unexpected object (with a Symbol(store-raw)) that breaks the segment.replace function. As a workaround, you can assign the function you need (like revokeOtherSessions in your Ember case) to a local variable before using it in your component. That same approach should help with your phoneNumber plugin OTP call.

Could you try extracting the relevant phone OTP sending function into a variable before using it from the router context? Let us know if that resolves the issue on your end. If you continue having difficulties, please tag @bekacru and @ping__ to help investigate further.

tag @better-auth-agent

DiagramDiscordGitHub

Diagram Join Star

@better-auth-agent[bot] commented on GitHub (Nov 4, 2025): Hi there, thanks for reporting this issue! It looks like the error occurs because when the authClient is placed into the Tanstack Router Solid context, the Solid store proxy interferes with the methods on authClient—specifically causing the phoneNumber plugin’s OTP function to receive an unexpected object (with a Symbol(store-raw)) that breaks the segment.replace function. As a workaround, you can assign the function you need (like revokeOtherSessions in your Ember case) to a local variable before using it in your component. That same approach should help with your phoneNumber plugin OTP call. Could you try extracting the relevant phone OTP sending function into a variable before using it from the router context? Let us know if that resolves the issue on your end. If you continue having difficulties, please tag @bekacru and @ping__ to help investigate further. tag @better-auth-agent <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) • [Discord](https://discord.gg/better-auth) • [GitHub](https://github.com/better-auth/better-auth) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/better-auth) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/better-auth/better-auth)
Author
Owner

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

Hi there! It looks like the error ("TypeError: segment.replace is not a function") occurs because when you pass the auth client through the router context, Solid’s store proxy wraps the object and modifies its properties (like adding a Symbol for the raw store), which then interferes with methods in the phone number plugin. In your case, calling the method directly (without the proxy) works fine, which reinforces that the proxy wrapping is causing the issue [1].

As a workaround, try extracting a local reference to the auth client (or the specific function you want to call) rather than accessing it directly through the router context. This seems to “unwrap” the proxied value so that the phone number OTP logic receives the expected plain string value for its operations. We’re aware that this isn’t ideal and adds extra pressure on the end user, so we’re investigating methods to make our API safe to use even when proxies are present in various environments [1], [2].

Can you confirm if this issue only occurs with the phone number plugin, or have you seen similar behavior with other Better Auth functions when used within the Solid context? tag @better-auth-agent

DiagramDiscordGitHub

Diagram Join Star

@better-auth-agent[bot] commented on GitHub (Nov 4, 2025): Hi there! It looks like the error ("TypeError: segment.replace is not a function") occurs because when you pass the auth client through the router context, Solid’s store proxy wraps the object and modifies its properties (like adding a Symbol for the raw store), which then interferes with methods in the phone number plugin. In your case, calling the method directly (without the proxy) works fine, which reinforces that the proxy wrapping is causing the issue [[1]](https://github.com/better-auth/better-auth/issues/4125). As a workaround, try extracting a local reference to the auth client (or the specific function you want to call) rather than accessing it directly through the router context. This seems to “unwrap” the proxied value so that the phone number OTP logic receives the expected plain string value for its operations. We’re aware that this isn’t ideal and adds extra pressure on the end user, so we’re investigating methods to make our API safe to use even when proxies are present in various environments [[1]](https://github.com/better-auth/better-auth/issues/4125), [[2]](https://github.com/better-auth/better-auth/issues/1155). Can you confirm if this issue only occurs with the phone number plugin, or have you seen similar behavior with other Better Auth functions when used within the Solid context? tag @better-auth-agent <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) • [Discord](https://discord.gg/better-auth) • [GitHub](https://github.com/better-auth/better-auth) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/better-auth) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/better-auth/better-auth)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#1085