Next.js Discord

Discord Forum

Dynamic API routes return 404 on Vercel but not locally (Next 14.0.1, app router)

Answered
Ben Greene posted this in #help-forum
Open in Discord
Avatar
Ben GreeneOP
Hi all - I have a very annoying error that I can't seem to fix. This is on Next 14.0.1 using app router.

The specific behavior is that certain API routes are returning 404 errors instead of loading, but only when deployed to Vercel. The attached image shows the directory structure of the API routes - the specific routes that fail are api/programs/[id] and api/programs/page/[page]. The api/users, api/users/[id], and api/programs routes all return results.

There does not appear to be any significant difference in the route.ts files. Does anyone have suggestions on what I could try?

Thank you 🙏
Image
Answered by Ben Greene
Update: although the why still eludes us, we were able to resolve the problem. The cause seems to be having a directory in the root of the project (at the same level as app) called api. This was being used for some library files. Renaming that directory from api to apiServices seems to be the only change required to make the dynamic routes begin functioning properly again.
View full answer

116 Replies

Avatar
Siricid woodwasp
where are you calling those apis in client or server?
Avatar
Ben GreeneOP
@Siricid woodwasp Sorry, I'm not completely sure I understand your question. Whether I make the API call from within a component or directly via the web browser, I get the 404 either way.
Avatar
Siricid woodwasp
i mean how are you calling api end points in your app like fetch("api/user")
Avatar
Ben GreeneOP
Ahh - const response = await get(programs/page/${page});
Avatar
Siricid woodwasp
are those client components?
Avatar
Ben GreeneOP
It's a lib used within client components, I believe - will need to check, currenly away from desk
Avatar
Ben GreeneOP
confimed, client components
but I'm fairly sure that the problem is somehow elsewhere, because accessing the API call directly from the browser also fails 😕
Avatar
Ben GreeneOP
@Siricid woodwasp I think I've made some progress - this seems to only hit API calls that have a dynamic element in them, e.g. programs/page/[page] - it turns out that users/[id] doesn't work either (on Vercel - still works fine locally).
Avatar
Northern snakehead
just going to jump in here and follow this as I believe i have the same issue 🙂
Avatar
Ben GreeneOP
I updated the title to be a bit more specific and hopefully garner more assistance 🙏
Avatar
Z4NR34L
Yo Folks. Let's solve this - at the beginning @Ben Greene, could you provide us with this endpoint code/repository url (if it's public) or minimal reproduction?

https://nextjs-faq.com/minimal-reproduction-repository
also if that's possible please share an screenshot of that 404 error which you get - this will help assign if we have problem with vercel (platform) or nextjs (your code)
Avatar
Ben GreeneOP
@Z4NR34L appreciate your help!
Here's a screenshot of the 404 on Vercel (left) and the 200 on localhost (right):
Image
The repo is not public, so it'll take me some time to create a new test repo
While I get that ready - my colleague believes that not having NEXT_PUBLIC_API_URL defined in the ENV variables may be a cause of this problem - could that be the case? And if so, how is one supposed to generate that in Vercel preview deployments?
Avatar
Z4NR34L
Ok, There is no chance to get into the cause of this issue without even minimal reproduction or code, we can just guess, and env variables is the first thing that should be double checked before deployment 😄
scan your code which env vars are you using, remember that if you use variable in route handler you dont need to add NEXT_PUBLIC_ prefix as it’s executed server-side
Avatar
Ben GreeneOP
lol yeah, I'm working on a repro now
Avatar
Z4NR34L
if you don't have any hardcoded credentials, just post endpoint code here, that should be fine for now
Avatar
Ben GreeneOP
Sure, so here is the contents of app/api/programs/page/[page]/route.ts:
import { PrismaClient } from '@prisma/client';
import { NextRequest, NextResponse } from "next/server";

const prisma = new PrismaClient();

export async function GET(request: NextRequest) {
  const prisma = new PrismaClient();
  const programs = await prisma.program.findMany();
  return NextResponse.json(programs);
}
Avatar
Z4NR34L
also check your env vars on vercel, if you have selected all needed environments (Development/Preview/Production)
Image
Avatar
Ben GreeneOP
And that exact same code works in app/api/programs/route.ts
Avatar
Z4NR34L
huh, I see
are you running prisma generate during the build step? 😄
Avatar
Ben GreeneOP
Image
Avatar
Z4NR34L
ok, did you checked env vars?
you need preview + production on vercerl to get it work there
Avatar
Ben GreeneOP
Well I don't have DATABASE_URL at all, but the above returns data from the DB on the non-dynamic route
I have POSTGRES_URL
Avatar
Z4NR34L
ok, I meant any env vars that are used there
first, let's try to check if everything is just building fine, replace this code with:

import { NextRequest, NextResponse } from "next/server";

export async function GET(request: NextRequest, {params}: { params: { page: number }}) {
  return NextResponse.json({page: params.page});
}


and verify if you get back number you provided in path
Avatar
Ben GreeneOP
pushed to vercel
still a 404
I'm not an expert on Next.js by any means, but I don't think the code content of the route itself is playing much of a role
Avatar
Z4NR34L
that's what we needed to verify
Now, please share your next.config and middleware (if any), also vercel.json if used
and to be sure, post file path in repository, and URL without domain
Avatar
Ben GreeneOP
next.config.js:
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
  images: {
    domains: ["lh3.googleusercontent.com", "vercel.com"],
  },
  async redirects() {
    return [
      {
        source: "/github",
        destination: "https://github.com/steven-tey/precedent",
        permanent: false,
      },
    ];
  },
};

module.exports = nextConfig;

(I should probably change that github source from the repo I cloned)
middleware.ts:
import createMiddleware from 'next-intl/middleware';
import { LOCALES } from '@/lib/constants';
 
export default createMiddleware({
  // A list of all locales that are supported
  locales: LOCALES,
 
  // If this locale is matched, pathnames work without a prefix (e.g. `/about`)
  defaultLocale: 'en'
});
 
export const config = {
  // Skip all paths that should not be internationalized. This example skips the
  // folders "api", "_next" and all files with an extension (e.g. favicon.ico)
  matcher: ['/((?!api|_next|.*\\..*).*)']
};
No vercel.json
Avatar
Z4NR34L
ok, so url without domain and file path in repository - just for double-check
also please check your vercel logs if there is no errors 😉
Avatar
Ben GreeneOP
the relative file path (copied from VS Code) is: app/api/programs/page/[page]/route.ts
And the URL without domain: /api/programs/page/1
the deployment logs say 0 errors and 0 warnings
I've read through it and not seen anything particularly interesting
although it does identify the routes in question:
Route (app)                              Size     First Load JS
┌ ○ /_not-found                          882 B          89.2 kB
├ λ /[locale]                            559 B           124 kB
├ λ /[locale]/about                      550 B           124 kB
├ λ /[locale]/auth/error                 957 B           124 kB
├ λ /[locale]/auth/signin                863 B           135 kB
├ λ /[locale]/auth/verify-request        1 kB            124 kB
├ λ /[locale]/programs                   2.24 kB         125 kB
├ λ /[locale]/programs/[id]              2.4 kB          125 kB
├ λ /[locale]/programs/edit/[id]         1.11 kB         227 kB
├ λ /[locale]/programs/new               572 B           227 kB
├ λ /[locale]/users/[id]/edit            1.59 kB         125 kB
├ λ /api/auth/[...nextauth]              0 B                0 B
├ λ /api/programs                        0 B                0 B
├ λ /api/programs/details/[id]           0 B                0 B
├ λ /api/programs/page/[page]            0 B                0 B
├ ○ /api/users                           0 B                0 B
└ λ /api/users/[id]                      0 B                0 B
+ First Load JS shared by all            88.3 kB
  ├ chunks/472-e4fe7de096be0269.js       33 kB
  ├ chunks/fd9d1056-1de2bf583fdbc1a8.js  53.2 kB
  ├ chunks/main-app-892c3dff08e9cd4c.js  232 B
  â”” chunks/webpack-fbec2224bf4eac50.js   1.87 kB
Avatar
Z4NR34L
huh
Avatar
Ben GreeneOP
sounds like we're on the same page
Avatar
Z4NR34L
wait a sec
I'm using dynamic route handlers in my projects but I see that there is small difference
I'm on edge runtime
try to change our test route to edge 😄

export const runtime = 'edge'
Avatar
Ben GreeneOP
It's off 🍿
👎 😞
Avatar
Z4NR34L
you are using next-auth
you are not locking those urls? 😄
Avatar
Ben GreeneOP
...?
Avatar
Z4NR34L
maybe I will ask in other words: are you using next-auth to auth users before accessing those routes?
I mean api routes
Avatar
Ben GreeneOP
oh - no, I'm not - though I certainly will down the line
Avatar
Z4NR34L
the problem is - I cannot reproduce that issue in clean next.js - so maybe one of packages that you had used is messing around
but let's try one more thing - remove middleware for now
just to get as clean access to route as possible
Avatar
Ben GreeneOP
What version of nextjs are you on
Avatar
Ray
do you see any errors from the logs on vercel dashboard?
Avatar
Ben GreeneOP
not really:
Image
though I didn't expect a 204...
Avatar
Z4NR34L
I'm using 14.0.2 currently
you are viewing a HEAD method request log, and you are supposed to make an GET method
Avatar
Ben GreeneOP
yeah.... weird
Avatar
Z4NR34L
but /api/programs is working fine from what I can see
Avatar
Ben GreeneOP
correct
Avatar
Z4NR34L
but, can you see more logs on vercel now?
Avatar
Ben GreeneOP
this is so bizarre
here's chrome inspector:
Image
but there's no corresponding 404 in vercel:
Image
I'm on 14.0.1, so I'm gonna upgrade that just to see
Avatar
Z4NR34L
there is still middleware that's working
try disabling/removing it for now
Avatar
Ben GreeneOP
sorry that middleware is from a different branch
Avatar
Z4NR34L
ok
I remember that I was not using next-intl for a reason with appdir 😄 But not sure what exacly problem that was
Avatar
Ben GreeneOP
::blinks::
Avatar
Z4NR34L
I've made my own middlware for locales routing
/api/users/[id] is not working too from what I checked now
Avatar
Ben GreeneOP
correct
no dynamic api route is
I wonder if it worked when I started this with 13.5......
Avatar
Z4NR34L
hmm, that's pretty wide problem, and I think I'm not able to help you without testing this right on your repository :/
Avatar
Ray
i can't reproduce it too
Avatar
Ben GreeneOP
Interesting.
Also interesting: after upgrading to 14.0.2, I now get this error:
app/api/auth/[...nextauth]/route.ts
Type error: Route "app/api/auth/[...nextauth]/route.ts" does not match the required types of a Next.js Route.
  "authOptions" is not a valid Route export field.
Avatar
Ben GreeneOP
^^^ this is not so much interesting as just annoying
Avatar
Ray
what version of next-auth are you using
Avatar
Ben GreeneOP
4.22.1
Avatar
Ray
does the api work if you change the middleware file to _middleware
Avatar
Ben GreeneOP
sorry had to get back to a working state - so just rename it to _middleware...
Avatar
Ben GreeneOP
I mean the short answer is that obviously kills my locale-enabled pages... working on actually getting a successful deploy through Vercel... been making a lot of changes quickly...
Ok! Results are in, and removing/renaming middleware file does not make the dynamic API routes functional.
Avatar
Z4NR34L
So that case too wide to debug it just by telling you what to do, badly. Easiest way would be making a reproduction or allowing us to view the origin code
Avatar
Ben GreeneOP
@Z4NR34L I DMed you
Avatar
Z4NR34L
Update: This topic is in progress - if we find a solution, I'll post it there
Avatar
Ben GreeneOP
Update: although the why still eludes us, we were able to resolve the problem. The cause seems to be having a directory in the root of the project (at the same level as app) called api. This was being used for some library files. Renaming that directory from api to apiServices seems to be the only change required to make the dynamic routes begin functioning properly again.
Answer
Avatar
Z4NR34L
brilliant 😄
Avatar
Ben GreeneOP
Right?! 😞
Avatar
Z4NR34L
that's perfect example why it's important for others to see whole code/repository or reproduction 😄
Avatar
Berger Picard
hey sorry to revive this, I'm having the exact same issue but with localhost
/api/players returns 404
Image
even in postman
its really bare too
Image
Avatar
risky
why are you not using route.ts as players.ts is going to be ignored.... also for future can you make a new thread as everyones are diferent
Avatar
Berger Picard
why
Avatar
risky
what do you mean by "why"?
your /api isn't going to be usable, idk if thats intentional