Clerk auth() called on a route with file extension in T3 stack

Hi all. Having some issues with T3 and Clerk when i navigate to a route with any extension '/foo.bar'. I get the following error:
Error: Clerk: auth() was called but Clerk can't detect usage of clerkMiddleware() (or the deprecated authMiddleware()). Please ensure the following:
- clerkMiddleware() (or the deprecated authMiddleware()) is used in your Next.js Middleware.
- Your Middleware matcher is configured to match this route or page.
- If you are using the src directory, make sure the Middleware file is inside of it.

For more details, see https://clerk.com/docs/quickstarts/nextjs
Error: Clerk: auth() was called but Clerk can't detect usage of clerkMiddleware() (or the deprecated authMiddleware()). Please ensure the following:
- clerkMiddleware() (or the deprecated authMiddleware()) is used in your Next.js Middleware.
- Your Middleware matcher is configured to match this route or page.
- If you are using the src directory, make sure the Middleware file is inside of it.

For more details, see https://clerk.com/docs/quickstarts/nextjs
I assume the middleware is working correctly as clerkMiddleware shouldn't be applied to this non existent route/file. Also if i type go to '/foo' i get the correct 404 page, served by not-found.tsx. Everything else is working in my app but it's just i'm seeing on my server logs when random bots are trying '/wp-login.php' it's reporting this error. So I'm wondering if it's something to do with tRPC setup in my T3 setup? Here is my src/middleware.ts:
import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server";
import { NextResponse } from "next/server";

const isProtectedRoute = createRouteMatcher([
"/dashboard(.*)",
]);

export default clerkMiddleware(
(auth, request) => {
const { userId } = auth();
if (userId && request.nextUrl.pathname === "/") {
return NextResponse.redirect(new URL("/dashboard", request.url));
}

if (isProtectedRoute(request)) {
auth().protect({
unauthenticatedUrl: request.nextUrl.origin + "/",
unauthorizedUrl: request.nextUrl.origin + "/",
});
}

return NextResponse.next();
},
{ debug: process.env.NODE_ENV === "development" },
);

export const config = {
matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
};
import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server";
import { NextResponse } from "next/server";

const isProtectedRoute = createRouteMatcher([
"/dashboard(.*)",
]);

export default clerkMiddleware(
(auth, request) => {
const { userId } = auth();
if (userId && request.nextUrl.pathname === "/") {
return NextResponse.redirect(new URL("/dashboard", request.url));
}

if (isProtectedRoute(request)) {
auth().protect({
unauthenticatedUrl: request.nextUrl.origin + "/",
unauthorizedUrl: request.nextUrl.origin + "/",
});
}

return NextResponse.next();
},
{ debug: process.env.NODE_ENV === "development" },
);

export const config = {
matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
};
3 Replies
chriskduffy77
chriskduffy77OP6mo ago
src/server/api/trpc.ts
import { initTRPC, TRPCError } from "@trpc/server";
import superjson from "superjson";
import { ZodError } from "zod";

import { auth } from "@clerk/nextjs/server";
import { db } from "../db";

export const createTRPCContext = async (opts: {
headers: Headers;
// eslint-disable-next-line @typescript-eslint/require-await
}) => {
return {
db,
auth: auth(),
...opts,
};
};

const t = initTRPC.context<typeof createTRPCContext>().create({
transformer: superjson,
errorFormatter({ shape, error }) {
return {
...shape,
data: {
...shape.data,
zodError:
error.cause instanceof ZodError ? error.cause.flatten() : null,
},
};
},
});

export const createCallerFactory = t.createCallerFactory;

export const createTRPCRouter = t.router;

export const publicProcedure = t.procedure;

const enforceUserIsAuthed = t.middleware(({ next, ctx }) => {
if (!ctx.auth.userId) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
ctx: {
auth: ctx.auth,
},
});
});
export const protectedProcedure = t.procedure.use(enforceUserIsAuthed);
import { initTRPC, TRPCError } from "@trpc/server";
import superjson from "superjson";
import { ZodError } from "zod";

import { auth } from "@clerk/nextjs/server";
import { db } from "../db";

export const createTRPCContext = async (opts: {
headers: Headers;
// eslint-disable-next-line @typescript-eslint/require-await
}) => {
return {
db,
auth: auth(),
...opts,
};
};

const t = initTRPC.context<typeof createTRPCContext>().create({
transformer: superjson,
errorFormatter({ shape, error }) {
return {
...shape,
data: {
...shape.data,
zodError:
error.cause instanceof ZodError ? error.cause.flatten() : null,
},
};
},
});

export const createCallerFactory = t.createCallerFactory;

export const createTRPCRouter = t.router;

export const publicProcedure = t.procedure;

const enforceUserIsAuthed = t.middleware(({ next, ctx }) => {
if (!ctx.auth.userId) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
ctx: {
auth: ctx.auth,
},
});
});
export const protectedProcedure = t.procedure.use(enforceUserIsAuthed);
/src/trpc/server.ts
import "server-only";

import { headers } from "next/headers";
import { cache } from "react";

import { createCaller } from "@/server/api/root";
import { createTRPCContext } from "@/server/api/trpc";
const createContext = cache(() => {
const heads = new Headers(headers());
heads.set("x-trpc-source", "rsc");

return createTRPCContext({
headers: heads,
});
});

export const api = createCaller(createContext);
import "server-only";

import { headers } from "next/headers";
import { cache } from "react";

import { createCaller } from "@/server/api/root";
import { createTRPCContext } from "@/server/api/trpc";
const createContext = cache(() => {
const heads = new Headers(headers());
heads.set("x-trpc-source", "rsc");

return createTRPCContext({
headers: heads,
});
});

export const api = createCaller(createContext);
src/trpc/react.tsx
"use client";

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { loggerLink, unstable_httpBatchStreamLink } from "@trpc/client";
import { createTRPCReact } from "@trpc/react-query";
import { type inferRouterInputs, type inferRouterOutputs } from "@trpc/server";
import { useState } from "react";
import SuperJSON from "superjson";

import { type AppRouter } from "@/server/api/root";

const createQueryClient = () =>
new QueryClient({});

let clientQueryClientSingleton: QueryClient | undefined = undefined;
const getQueryClient = () => {
if (typeof window === "undefined") {
return createQueryClient();
}
return (clientQueryClientSingleton ??= createQueryClient());
};
export const api = createTRPCReact<AppRouter>();
export type RouterInputs = inferRouterInputs<AppRouter>;
export type RouterOutputs = inferRouterOutputs<AppRouter>;

export function TRPCReactProvider(props: { children: React.ReactNode }) {
const queryClient = getQueryClient();

const [trpcClient] = useState(() =>
api.createClient({
links: [
loggerLink({
enabled: (op) =>
process.env.NODE_ENV === "development" ||
(op.direction === "down" && op.result instanceof Error),
}),
unstable_httpBatchStreamLink({
transformer: SuperJSON,
url: getBaseUrl() + "/api/trpc",
headers: () => {
const headers = new Headers();
headers.set("x-trpc-source", "nextjs-react");
return headers;
},
}),
],
}),
);
return (
<QueryClientProvider client={queryClient}>
<api.Provider client={trpcClient} queryClient={queryClient}>
{props.children}
</api.Provider>
</QueryClientProvider>
);
}
"use client";

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { loggerLink, unstable_httpBatchStreamLink } from "@trpc/client";
import { createTRPCReact } from "@trpc/react-query";
import { type inferRouterInputs, type inferRouterOutputs } from "@trpc/server";
import { useState } from "react";
import SuperJSON from "superjson";

import { type AppRouter } from "@/server/api/root";

const createQueryClient = () =>
new QueryClient({});

let clientQueryClientSingleton: QueryClient | undefined = undefined;
const getQueryClient = () => {
if (typeof window === "undefined") {
return createQueryClient();
}
return (clientQueryClientSingleton ??= createQueryClient());
};
export const api = createTRPCReact<AppRouter>();
export type RouterInputs = inferRouterInputs<AppRouter>;
export type RouterOutputs = inferRouterOutputs<AppRouter>;

export function TRPCReactProvider(props: { children: React.ReactNode }) {
const queryClient = getQueryClient();

const [trpcClient] = useState(() =>
api.createClient({
links: [
loggerLink({
enabled: (op) =>
process.env.NODE_ENV === "development" ||
(op.direction === "down" && op.result instanceof Error),
}),
unstable_httpBatchStreamLink({
transformer: SuperJSON,
url: getBaseUrl() + "/api/trpc",
headers: () => {
const headers = new Headers();
headers.set("x-trpc-source", "nextjs-react");
return headers;
},
}),
],
}),
);
return (
<QueryClientProvider client={queryClient}>
<api.Provider client={trpcClient} queryClient={queryClient}>
{props.children}
</api.Provider>
</QueryClientProvider>
);
}
I've omitted getBaseUrl because of char count. All stnadard t3 app stuff. And finally here's my errors on the server when i try to navigate to '/wp-login.php'
⨯ Error: Clerk: auth() was called but Clerk can't detect usage of clerkMiddleware() (or the deprecated authMiddleware()). Please ensure the following:
- clerkMiddleware() (or the deprecated authMiddleware()) is used in your Next.js Middleware.
- Your Middleware matcher is configured to match this route or page.
- If you are using the src directory, make sure the Middleware file is inside of it.

For more details, see https://clerk.com/docs/quickstarts/nextjs

at stringify (<anonymous>)
at stringify (<anonymous>)
at stringify (<anonymous>)
digest: "4238218138"
⨯ Error: Clerk: auth() ....SAME ERROR AS BEFORE
digest: "4238218138"
GET /wp-login.php 404 in 55ms
⨯ Error: Clerk: auth() ....SAME ERROR AS BEFORE
digest: "4238218138"
⨯ Error: Clerk: auth() ....SAME ERROR AS BEFORE
digest: "4238218138"
GET /_next/static/chunks/app/invalidateCache.js.map 404 in 187ms
⨯ Error: Clerk: auth() was called but Clerk can't detect usage of clerkMiddleware() (or the deprecated authMiddleware()). Please ensure the following:
- clerkMiddleware() (or the deprecated authMiddleware()) is used in your Next.js Middleware.
- Your Middleware matcher is configured to match this route or page.
- If you are using the src directory, make sure the Middleware file is inside of it.

For more details, see https://clerk.com/docs/quickstarts/nextjs

at stringify (<anonymous>)
at stringify (<anonymous>)
at stringify (<anonymous>)
digest: "4238218138"
⨯ Error: Clerk: auth() ....SAME ERROR AS BEFORE
digest: "4238218138"
GET /wp-login.php 404 in 55ms
⨯ Error: Clerk: auth() ....SAME ERROR AS BEFORE
digest: "4238218138"
⨯ Error: Clerk: auth() ....SAME ERROR AS BEFORE
digest: "4238218138"
GET /_next/static/chunks/app/invalidateCache.js.map 404 in 187ms
I'm also using the following:
"@clerk/nextjs": "^5.1.5", "@trpc/client": "next",
"@trpc/react-query": "next",
"@trpc/server": "next","next": "^14.2.4",
"@clerk/nextjs": "^5.1.5", "@trpc/client": "next",
"@trpc/react-query": "next",
"@trpc/server": "next","next": "^14.2.4",
So i'm setup for the Clerk core 2 stuff... Oh and my 404 page:
import Image from "next/image";
import Link from "next/link";
import NotFoundImage from "/public/404.webp";

export default function NotFound() {
return (
<div className="flex max-h-screen flex-col items-center justify-center bg-white text-center">
<div className="flex w-full flex-col items-center">
<div className="flex max-w-2xl items-center justify-center">
<Image src={NotFoundImage} alt="Page Not Found" priority />
</div>
<span>
Designed by{" "}
<Link
prefetch={false}
className="text-blue-400"
href={"www.freepik.com"}
>
Freepik
</Link>
</span>
<h1 className="mt-8 text-4xl font-bold text-gray-800">
Page Not Found
</h1>
<p className="mt-4 text-gray-600">
Oops! The page you are looking for does not exist. It might have been
moved or deleted.
</p>
<Link href="/">Home</Link>
</div>
</div>
);
}
import Image from "next/image";
import Link from "next/link";
import NotFoundImage from "/public/404.webp";

export default function NotFound() {
return (
<div className="flex max-h-screen flex-col items-center justify-center bg-white text-center">
<div className="flex w-full flex-col items-center">
<div className="flex max-w-2xl items-center justify-center">
<Image src={NotFoundImage} alt="Page Not Found" priority />
</div>
<span>
Designed by{" "}
<Link
prefetch={false}
className="text-blue-400"
href={"www.freepik.com"}
>
Freepik
</Link>
</span>
<h1 className="mt-8 text-4xl font-bold text-gray-800">
Page Not Found
</h1>
<p className="mt-4 text-gray-600">
Oops! The page you are looking for does not exist. It might have been
moved or deleted.
</p>
<Link href="/">Home</Link>
</div>
</div>
);
}
Thanks for any help in advance...oh and one other maybe curious thing is that i can't make the 404 page static...if i try and 'force-static' I get the same type of error. All my pages are ending up dynamic even though the not-found definitely shouldn't be. This happens when I build or in dev. Thanks Chris
chriskduffy77
chriskduffy77OP6mo ago
Hey sorry just as a follow up: I think it was because I was using some Clerk auth components in my NavBar component that was then being called on any route:
<ClerkProvider
appearance={{
layout: {
termsPageUrl: "/terms",
privacyPageUrl: "/privacy",
shimmer: true,
},
}}
>
<Navbar />
<TRPCReactProvider>
<div
className={cn(
"bg-muted/40, min-h-screen font-sans antialiased",
inter.variable,
)}
>
{children}
</div>
<Toaster position="bottom-right" richColors closeButton />
{process.env.NODE_ENV === "development" && (
<ReactQueryDevtools position="bottom" initialIsOpen={false} />
)}
</TRPCReactProvider>
</ClerkProvider>
<ClerkProvider
appearance={{
layout: {
termsPageUrl: "/terms",
privacyPageUrl: "/privacy",
shimmer: true,
},
}}
>
<Navbar />
<TRPCReactProvider>
<div
className={cn(
"bg-muted/40, min-h-screen font-sans antialiased",
inter.variable,
)}
>
{children}
</div>
<Toaster position="bottom-right" richColors closeButton />
{process.env.NODE_ENV === "development" && (
<ReactQueryDevtools position="bottom" initialIsOpen={false} />
)}
</TRPCReactProvider>
</ClerkProvider>
I've now stripped out any sort of auth checking logic from the Navbar...a bit of a shame because i wanted to check if a User was signed in and display diffferent things there. I'm sure there's a way..link to repo that helped me figure it out: https://github.com/orgs/clerk/discussions/1764 I'm now able to render statically with force-static (The ClerkProvider renders everything dynamic unless yo specify otherwise which is also a little bit of a pain)
GitHub
ClerkProvider Should Not Force All Children to Render Dynamically ·...
Preliminary Checks I have reviewed the documentation: https://clerk.com/docs I have searched for existing issues: https://github.com/clerkinc/javascript/issues This issue is not a question, general...
chriskduffy77
chriskduffy77OP6mo ago
For anyone reading through: I was able to get the behaviour i wanted by making the NavBar a client component
Want results from more Discord servers?
Add your server