[GH-ISSUE #3036] node:internal/process/promises:394 triggerUncaughtException(err, true /* fromPromise */); ^ [APIError] { status: 'UNAUTHORIZED', #26765

Closed
opened 2026-04-17 17:26:48 -05:00 by GiteaMirror · 2 comments
Owner

Originally created by @jpainam on GitHub (Jun 15, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/3036

This APIError errors but the trpc queries runs and execute.

 GET /api/trpc/.... 200 in 698ms
node:internal/process/promises:394
    triggerUncaughtException(err, true /* fromPromise */);
    ^

[APIError] {
  status: 'UNAUTHORIZED',
  body: undefined,
  headers: {},
  statusCode: 401
}

Node.js v23.9.0
[TRPC]...... took 133ms to execute
 GET /api/trpc/...... n 183ms
node:internal/process/promises:394
    triggerUncaughtException(err, true /* fromPromise */);
    ^

[APIError] {
  status: 'UNAUTHORIZED',
  body: undefined,
  headers: {},
  statusCode: 401
}

Node.js v23.9.0
[TRPC] year.all took 206ms to execute

I have a single place where i throw `UNAUTHORIZED

export const protectedProcedure = t.procedure
  .use(timingMiddleware)
  .use(async ({ ctx, next }) => {
    if (!ctx.session?.user) {
      throw new TRPCError({ code: "UNAUTHORIZED" });
    }
   
    return next({
      ctx: {
        // infers the `session` as non-nullable
        session: { ...ctx.session, user: ctx.session.user },
      },
    });
  });

My middleware

import { getSessionCookie } from "better-auth/cookies";
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";

// Define which paths should skip the middleware
export const config = {
  matcher: [
    "/((?!api|_next/static|_next/image|images|fonts|favicon.ico|manifest.webmanifest|robots.txt).*)",
  ],
};

// These routes don't require auth
const unProtectedRoutes = [
  "/auth",
  "/manifest.webmanifest",
  "/favicon.ico",
  "/robots.txt",
];

// eslint-disable-next-line @typescript-eslint/require-await
export async function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;
  const isProtectedRoute = !unProtectedRoutes.some((route) =>
    pathname.startsWith(route),
  );
 
  const session = getSessionCookie(request);
  if (isProtectedRoute && !session) {
    return NextResponse.redirect(new URL("/auth/login", request.url));
  }
  return NextResponse.next();
}
Originally created by @jpainam on GitHub (Jun 15, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/3036 This APIError errors but the trpc queries runs and execute. ```tsx GET /api/trpc/.... 200 in 698ms node:internal/process/promises:394 triggerUncaughtException(err, true /* fromPromise */); ^ [APIError] { status: 'UNAUTHORIZED', body: undefined, headers: {}, statusCode: 401 } Node.js v23.9.0 [TRPC]...... took 133ms to execute GET /api/trpc/...... n 183ms node:internal/process/promises:394 triggerUncaughtException(err, true /* fromPromise */); ^ [APIError] { status: 'UNAUTHORIZED', body: undefined, headers: {}, statusCode: 401 } Node.js v23.9.0 [TRPC] year.all took 206ms to execute ``` I have a single place where i throw `UNAUTHORIZED ```tsx export const protectedProcedure = t.procedure .use(timingMiddleware) .use(async ({ ctx, next }) => { if (!ctx.session?.user) { throw new TRPCError({ code: "UNAUTHORIZED" }); } return next({ ctx: { // infers the `session` as non-nullable session: { ...ctx.session, user: ctx.session.user }, }, }); }); ``` My middleware ```tsx import { getSessionCookie } from "better-auth/cookies"; import type { NextRequest } from "next/server"; import { NextResponse } from "next/server"; // Define which paths should skip the middleware export const config = { matcher: [ "/((?!api|_next/static|_next/image|images|fonts|favicon.ico|manifest.webmanifest|robots.txt).*)", ], }; // These routes don't require auth const unProtectedRoutes = [ "/auth", "/manifest.webmanifest", "/favicon.ico", "/robots.txt", ]; // eslint-disable-next-line @typescript-eslint/require-await export async function middleware(request: NextRequest) { const { pathname } = request.nextUrl; const isProtectedRoute = !unProtectedRoutes.some((route) => pathname.startsWith(route), ); const session = getSessionCookie(request); if (isProtectedRoute && !session) { return NextResponse.redirect(new URL("/auth/login", request.url)); } return NextResponse.next(); } ```
GiteaMirror added the locked label 2026-04-17 17:26:48 -05:00
Author
Owner

@jpainam commented on GitHub (Jun 15, 2025):

BTW, this happens as soon as I run pnpm dev without even opening localhost:3000

This is the error i get in production

[Error [APIError]: ] {
  status: 'UNAUTHORIZED',
  body: undefined,
  headers: {},
  statusCode: 401
}
This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason:

  unhandledRejection:  [Error [APIError]: ] {
  status: 'UNAUTHORIZED',
  body: undefined,
  headers: {},
  statusCode: 401
}
[Error [APIError]: ] {
  status: 'UNAUTHORIZED',
  body: undefined,
  headers: {},
  statusCode: 401
}
This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason:

  unhandledRejection:  [Error [APIError]: ] {
  status: 'UNAUTHORIZED',
  body: undefined,
  headers: {},
  statusCode: 401
}
<!-- gh-comment-id:2974134604 --> @jpainam commented on GitHub (Jun 15, 2025): BTW, this happens as soon as I run `pnpm dev` without even opening `localhost:3000` This is the error i get in production ```tsx [Error [APIError]: ] { status: 'UNAUTHORIZED', body: undefined, headers: {}, statusCode: 401 } This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason: ⨯ unhandledRejection: [Error [APIError]: ] { status: 'UNAUTHORIZED', body: undefined, headers: {}, statusCode: 401 } [Error [APIError]: ] { status: 'UNAUTHORIZED', body: undefined, headers: {}, statusCode: 401 } This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason: ⨯ unhandledRejection: [Error [APIError]: ] { status: 'UNAUTHORIZED', body: undefined, headers: {}, statusCode: 401 } ```
Author
Owner

@jpainam commented on GitHub (Jun 15, 2025):

For anyone experiencing the same issue. ,make sure to wrap every auth.api calls within a try/catch. it silently throw error.

<!-- gh-comment-id:2974525576 --> @jpainam commented on GitHub (Jun 15, 2025): For anyone experiencing the same issue. ,make sure to wrap every `auth.api` calls within a `try/catch`. it silently throw error.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#26765