Next.js Discord

Discord Forum

Uploading a File through a Server Action takes forever

Unanswered
Cinnamon posted this in #help-forum
Open in Discord
CinnamonOP
I currently port over some code to Nextjs Server Actions. I have a Frontend Form that submits a file, I wanna upload that file to my 3rd party API. But the request takes over 4 Minutes before it probably times out.

export async function uploadDocument(formData: FormData) {
  const projectId = z.string().parse(formData.get("projectId"));
  const file = formData.get("file") as File;

  const bearer = await getBearer();

  try {
    await fetch(
      `https://apiurl.com/Project/${projectId}/container/${file.name}`,
      {
        method: "POST",
        body: formData,
        credentials: "include",
        headers: {
          Authorization: `Bearer ${bearer}`,
        },
      },
    );

    revalidatePath(`/project/${projectId}/documents`);

    return { ok: true };
  } catch (e) {
    console.log(e);
    return { ok: false };
  }
}


I get no errors. Any idea what causes it?

58 Replies

CinnamonOP
Payload is
https:apiurl.com isn't a correct url (but i think that isn't the issue)
CinnamonOP
I just replaced the real url in the snippet
Corrected it 😅
i meant not having :// but i gathered it was fake
if on vercel, server actions can only last 10 secs
CinnamonOP
its in dev currently
ahh but, 4 mins is decent length
CinnamonOP
its just a 400KB file and in my old remix action handler this was done in like under a second so there must be some issue hidden in the code
Only info I get in the console after the thing is finally run is this:
you should prob fix the revalidatetags issue (whereever that is)
@Cinnamon its in dev currently
try in prod (next build && next start) as the dev can be slow for things like api routes
CinnamonOP
weird thing is I dont even use revalidateTags
This appears after exactly 4.0 Minutes, everytime.
Response:
0:["$@1",["development",null]]
1:{"ok":true}
Its really weird that it goes through. Let me check in built mode.
@Cinnamon weird thing is I dont even use revalidateTags
anywhere else in your code?
and your using latest nextjs version right? (edit: i can see it is latest)
CinnamonOP
So in the built verision the same issue appears, I do not have any revalidateTagsin the codebase, I just commented out the revalidatePathsbut it makes no difference.
and if you console log before and after the fetch req, how far apart are the logs
CinnamonOP
I just added a console timer, running currently.
  console.time("upload");

  console.timeLog("upload", "uploading file");
  try {
    await fetch(
      `https://apiurl.com/Project/${projectId}/container/${file.name}`,
      {
        method: "POST",
        body: formData,
        credentials: "include",
        headers: {
          "Content-Type": "multipart/form-data",
          Authorization: `Bearer ${bearer}`,
        },
      },
    );

    console.timeEnd("upload");
upload: 0.036ms uploading file
so thats fast
try putting the same type of code around other parts of the function (and at the very start and end)
CinnamonOP
just fyi the file never arrives on the server, but for some reason the function still returns the { ok: true } to the frontend after the 4 minutes.
if you get the response of the fetch, what do you get?
const res = await fetch()
console.log({status: res.status, msg: res.text()})
CinnamonOP
export async function uploadDocument(formData: FormData) {
  console.time("upload");

  const projectId = z.string().parse(formData.get("projectId"));
  const file = formData.get("file") as File;

  const bearer = await getBearer();

  console.timeLog("upload", "got auth token");
  try {
    const res = await fetch(
      `https://apiurl.net/Project/${projectId}/container/${file.name}`,
      {
        method: "POST",
        body: formData,
        credentials: "include",
        headers: {
          "Content-Type": "multipart/form-data",
          Authorization: `Bearer ${bearer}`,
        },
      },
    );

    console.log({ status: res.status, msg: res.text() });

    console.timeLog("upload", "file ulpaded");

    return { ok: true };
  } catch (e) {
    console.timeLog("upload", "arrived in the catch");
    console.log(e);
    return { ok: false };
  } finally {
    console.timeEnd("upload");
  }
}
Running right now.
upload: 2.328ms got auth token
after the 4 mins are passed I will try to send the body explicitly instead of just passing the formdata from the payload.
maybe that will work.
this is weird... also the finally might not be run because you return (but idk fully about that)
CinnamonOP
so I just get back a 408error
as the response status
as in your server action didn't respond?
or the fetch req
CinnamonOP
fetch req
and how long did the fetch req take?
CinnamonOP
it always takes 4.0 then it timeouts.
minutes
@Cinnamon `upload: 0.036ms uploading file`
you said this speed tho
as that sounds like an issue with the 3rd party (as nextjs fetch isn't that bad i didn't think...)
@riský you said this speed tho
CinnamonOP
this was just the timeLog before the fetch was called
ohh
CinnamonOP
yes I also though that, but I have the working remix app on my machine as well, and this is the code from the remix action:
    const file = formData.get("file") as File;
    const filename = file.name;

    const response = await fetch(
      `https://apiurl..../Project/${projectId}/container/${filename}`,
      {
        method: "POST",
        body: formData,
        credentials: "include",
        headers: getAuthHeader(context),
      },
    );

    if (!response.ok) {
      throw response;
    }
also shouldn't you create a buffer from formdata to send?
CinnamonOP
So it makes no sense to me why the fetch behaves so strange
the only diference i can see is: "Content-Type": "multipart/form-data", but im guessing getAuthHeader creates it
CinnamonOP
Ahh... I dont find any reason
I will set up a reproducable example and create an issue. In the meantime I will just call it from the client side.
Its the only file upload I have in the application currently.
Just need to find an api to demonstrate the upload on D:
this is partly why i use https://uploadthing.com/ now, because i don't need to worry about all this forwarding of files (not trying to advertise, just mentioning how i got around needing to deal with it)
CinnamonOP
now from the client it works seemlessly, must be some form of fetch passing the file
that makes this behaviour
server actions really be weird 😭 (ig thats why they are in beta)