Catching net::ERR_CONNECTION_REFUSED, with authClient?

Using authClient fort signIn:
const { data, error } = await authClient.signIn.email({
email: f.data.email,
password: f.data.password,
rememberMe: f.data.rememberMe,
});
const { data, error } = await authClient.signIn.email({
email: f.data.email,
password: f.data.password,
rememberMe: f.data.rememberMe,
});
I am hypothetically testing if my api is down. Why doesn't better-auth return better errors for this? I wrapped in try catch and no error seems to be thrown. Only see net::ERR_CONNECTION_REFUSED in console How can I reliably check for extraneous errors like network? 1. data returns null 2. error returns
{
"status": 0,
"statusText": ""
}
{
"status": 0,
"statusText": ""
}
Reliable way to check if data null then or when error.status === 0? Something is wrong error? I think authClient should at least throw an error so a catch block can take it.
17 Replies
nikatune
nikatune2mo ago
you can use onError : (err) => {}
const { data, error } = await authClient.signIn.email({
email: f.data.email,
password: f.data.password,
rememberMe: f.data.rememberMe,
} , {
onError: (err) => {
console.log(err);
}
});
const { data, error } = await authClient.signIn.email({
email: f.data.email,
password: f.data.password,
rememberMe: f.data.rememberMe,
} , {
onError: (err) => {
console.log(err);
}
});
Acro
AcroOP2mo ago
Do I need to handle error returned at the top not?
nikatune
nikatune2mo ago
probably its broken, you can use onError
Acro
AcroOP2mo ago
I don’t follow. What is the difference between returned error from function and onError
nikatune
nikatune2mo ago
its same
LightTab2
LightTab22mo ago
It has try catch block inside and it handles the error you want to handle. This is the boilerplate I use when I want to return error as part of function:
try
{
await authClient.resetPassword(
{
newPassword: data.newPassword,
token: data.resetToken,
fetchOptions:
{
onError(ctx)
{
throw (ctx.error?.message || 'Internal server error');
}
}
});
}
catch (err: unknown)
{
const errorMessage: (string | undefined) = err as string;
if (!errorMessage)
console.error(err);

return {
error: true,
message: (errorMessage || 'Internal server error')
};
}
try
{
await authClient.resetPassword(
{
newPassword: data.newPassword,
token: data.resetToken,
fetchOptions:
{
onError(ctx)
{
throw (ctx.error?.message || 'Internal server error');
}
}
});
}
catch (err: unknown)
{
const errorMessage: (string | undefined) = err as string;
if (!errorMessage)
console.error(err);

return {
error: true,
message: (errorMessage || 'Internal server error')
};
}
I blame javascript not better-auth for this
tacit_danger
tacit_danger4w ago
sounds like a bad idea in my opinion, i had a 401 unauthorized error that got classified as internal server error
async function doUpdatePassword() {
try {
const currentPassword = 'abcdefghi';
const newPassword = '123456789';
const response = await client.changePassword({
currentPassword,
fetchOptions: {
onError(ctx) {
throw ctx.error?.message || 'Internal server error';
}
},
newPassword,
revokeOtherSessions: true
});
console.log(response.token, response.user, 'do update password');
} catch (err) {
const errorMessage: string | undefined = err as string;
if (!errorMessage) console.error(err);

return {
error: true,
message: errorMessage || 'Internal server error'
};
}
}

async function onSubmit() {
const response = await doUpdatePassword();
console.log(response);
}
async function doUpdatePassword() {
try {
const currentPassword = 'abcdefghi';
const newPassword = '123456789';
const response = await client.changePassword({
currentPassword,
fetchOptions: {
onError(ctx) {
throw ctx.error?.message || 'Internal server error';
}
},
newPassword,
revokeOtherSessions: true
});
console.log(response.token, response.user, 'do update password');
} catch (err) {
const errorMessage: string | undefined = err as string;
if (!errorMessage) console.error(err);

return {
error: true,
message: errorMessage || 'Internal server error'
};
}
}

async function onSubmit() {
const response = await doUpdatePassword();
console.log(response);
}
tacit_danger
tacit_danger4w ago
No description
tacit_danger
tacit_danger4w ago
now lets try shutting the API backend down completely and see what error it throws
tacit_danger
tacit_danger4w ago
No description
tacit_danger
tacit_danger4w ago
same thing again - i am not an expert at this stuff by any means but i have a far better method i believe feel free to correct or improve
<script lang="ts">
import { BetterAuthError } from 'better-auth';
import { BetterFetchError } from '@better-fetch/fetch';
import { client } from '$lib/auth/client';

function doUpdatePassword() {
const currentPassword = 'abcdefghi';
const newPassword = '123456789';
return client.changePassword({
currentPassword,
newPassword,
revokeOtherSessions: true
});
}

async function onSubmit() {
try {
const response = await doUpdatePassword();
console.log(response.token, response.user, 'vow');
} catch (error) {
if (error instanceof BetterAuthError) {
console.log('it is a better auth error', error);
} else if (error instanceof BetterFetchError && error.status > 0) {
console.log(
'it is a better fetch error',
`NAME:${error.name} STATUS:${error.status} STATUS_TEXT:${error.statusText} ${error.statusText.length}`
);
} else if (error instanceof BetterFetchError && error.status === 0) {
console.log(
'network error',
`NAME:${error.name} STATUS:${error.status} STATUS_TEXT:${error.statusText} ${error.statusText.length}`
);
} else {
console.log('no idea', error);
}
}
}
</script>

<form onsubmit={onSubmit}>
<button>Update Password</button>
</form>
<script lang="ts">
import { BetterAuthError } from 'better-auth';
import { BetterFetchError } from '@better-fetch/fetch';
import { client } from '$lib/auth/client';

function doUpdatePassword() {
const currentPassword = 'abcdefghi';
const newPassword = '123456789';
return client.changePassword({
currentPassword,
newPassword,
revokeOtherSessions: true
});
}

async function onSubmit() {
try {
const response = await doUpdatePassword();
console.log(response.token, response.user, 'vow');
} catch (error) {
if (error instanceof BetterAuthError) {
console.log('it is a better auth error', error);
} else if (error instanceof BetterFetchError && error.status > 0) {
console.log(
'it is a better fetch error',
`NAME:${error.name} STATUS:${error.status} STATUS_TEXT:${error.statusText} ${error.statusText.length}`
);
} else if (error instanceof BetterFetchError && error.status === 0) {
console.log(
'network error',
`NAME:${error.name} STATUS:${error.status} STATUS_TEXT:${error.statusText} ${error.statusText.length}`
);
} else {
console.log('no idea', error);
}
}
}
</script>

<form onsubmit={onSubmit}>
<button>Update Password</button>
</form>
- catches all the errors perfectly as far as i tested you need to install @better-fetch/fetch separately it seems in order to import BetterFetchError, unbelievable that they have not exported this error from better-auth
tacit_danger
tacit_danger4w ago
No description
tacit_danger
tacit_danger4w ago
when there is a network error this one clearly indicates it
tacit_danger
tacit_danger4w ago
No description
tacit_danger
tacit_danger4w ago
also highlights the unauthorized error clearly but i gotta admit, status === 0 is absolutely the stupidest check i've had to do in a long freaking time
LightTab2
LightTab24w ago
Yes I don't really need to distinguish errors in my case other that the validation ones (which have descriptive messages) because I don't need it... You can do the check on ctx.status in the onError(ctx) too and I believe it would work. This looks better, I think I'll use that too as a good practice, thanks!
tacit_danger
tacit_danger4w ago
so apart from doing status.code === 0 for a network error check, is there really no better way? - Final update, i refactored a lot of stuff, this is the best i have come up with in terms of error handling - it distinguishes network errors from better auth errors from better fetch errors big time
import { BetterAuthError } from 'better-auth';
import { BetterFetchError } from '@better-fetch/fetch';
import { client } from '$lib/auth/client';
import { getErrorMessage, hasCodeAndMessage, hasOnlyMessage } from '$lib/auth/errors';

function doForgotPassword() {
const email = 'abc@example.com';
return client.forgetPassword({ email, redirectTo: '/' });
}

async function onSubmit() {
try {
const response = await doForgotPassword();
console.log(response.status, 'success');
} catch (error) {
if (error instanceof BetterAuthError) {
console.log('better auth error', JSON.stringify(error));
} else if (
error instanceof BetterFetchError &&
error.status > 0 &&
hasCodeAndMessage(error)
) {
console.log(
'better fetch error 1',
JSON.stringify(error),
getErrorMessage(error.error.code, 'en')
);
} else if (error instanceof BetterFetchError && error.status > 0 && hasOnlyMessage(error)) {
console.log('better fetch error 2', JSON.stringify(error), error.error.message);
} else if (error instanceof BetterFetchError && error.status === 0) {
console.log('network error', error);
} else {
console.log('unknown error', error);
}
}
}
import { BetterAuthError } from 'better-auth';
import { BetterFetchError } from '@better-fetch/fetch';
import { client } from '$lib/auth/client';
import { getErrorMessage, hasCodeAndMessage, hasOnlyMessage } from '$lib/auth/errors';

function doForgotPassword() {
const email = 'abc@example.com';
return client.forgetPassword({ email, redirectTo: '/' });
}

async function onSubmit() {
try {
const response = await doForgotPassword();
console.log(response.status, 'success');
} catch (error) {
if (error instanceof BetterAuthError) {
console.log('better auth error', JSON.stringify(error));
} else if (
error instanceof BetterFetchError &&
error.status > 0 &&
hasCodeAndMessage(error)
) {
console.log(
'better fetch error 1',
JSON.stringify(error),
getErrorMessage(error.error.code, 'en')
);
} else if (error instanceof BetterFetchError && error.status > 0 && hasOnlyMessage(error)) {
console.log('better fetch error 2', JSON.stringify(error), error.error.message);
} else if (error instanceof BetterFetchError && error.status === 0) {
console.log('network error', error);
} else {
console.log('unknown error', error);
}
}
}
- I really wish better-auth would document how to do all this stuff yourself, cant find a single mention of how to separate errors, what are the types of errors to expect from the client, no word, nada - also it is absolutely lame that i hvae to install @better-fetch/fetch just to import betterFetchError that better-auth throws every second, someone really needs to look into this one

Did you find this page helpful?