Next.js Discord

Discord Forum

vercel and s3 bucket not working?

Answered
Waterman posted this in #help-forum
Open in Discord
Avatar
WatermanOP
Hello, I have an admin panel where I upload images to my s3 bucket and I am 99% sure that I have everything correct in my s3 bucket policy configuration, everything is allowed and it works perfectly in dev(localhost) but once I head to my deployed version at my vercel on my own domain, it just doesn't upload the images, I don't know what goes wrong because I can't see any logs in production right? So does anyone know about this issue?
Answered by linesofcode
😅
View full answer

69 Replies

Avatar
linesofcode
You can see production logs in vercel
They remain for 1 hour
Just go your deployment page in the vercel dashboard and click on the logs tab
Are you sure you added the aws env keys for s3?
And that they aren’t using a reserved env variable name
That vercel uses internally
Avatar
WatermanOP
the only logs I get is the next/image error because the image doesn't exist cause the image didn't get uploaded.
because I don't get any errors that has to do with aws s3 or the actual upload
it would make sence though if it was the env but I dont' really understand what you mean with reserved env variable name
here is a screenshot of the env, the names are correct and the env is correct?
Image
Avatar
linesofcode
Yep that’s good
Avatar
WatermanOP
I really don't know what to do because it always works in dev and I have a cors configuration that allows everything
Avatar
linesofcode
This is what I was referring to
Avatar
WatermanOP
so have I done something wrong?
Avatar
linesofcode
Not from what I can tell
But it really depends on your code
Avatar
WatermanOP
you want me to share it?
Avatar
linesofcode
The more info you can provide the better yeah
Avatar
WatermanOP
import { NextRequest, NextResponse } from "next/server";
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { getServerSession } from "next-auth";
import { authOptions } from "../auth/[...nextauth]/route";

export const POST = async (req: NextRequest) => {
  const session = await getServerSession(authOptions);

  if (!session) {
    throw "Not Admin";
  }

  const formData = await req.formData();

  const client = new S3Client({
    region: "eu-north-1",
    credentials: {
      accessKeyId: process.env.S3_ACCESS_KEY || "",
      secretAccessKey: process.env.S3_SECRET_ACCESS_KEY || "",
    },
  });

  const links = [];

  for (const file of formData.getAll("file")) {
    const blob = file as Blob; // Assert that file is a Blob.
    const ext = blob.type?.split("/").pop();
    const newFileName = `${Date.now()}-${Math.random()
      .toString(36)
      .substring(2, 15)}.${ext}`;

    const fileBuffer = Buffer.from(await blob.arrayBuffer()); // Use Buffer.from to convert ArrayBuffer to Buffer.
    const fileUint8Array = new Uint8Array(fileBuffer);

    client.send(
      new PutObjectCommand({
        Bucket: "nextjsleflyxbuckle",
        Key: newFileName,
        Body: fileUint8Array,
        ACL: "public-read",
        ContentType: blob.type,
      })
    );
    const link = `https://nextjsleflyxbuckle.s3.eu-north-1.amazonaws.com/${newFileName}`;
    links.push(link);
  }

  return NextResponse.json({ links });
};
just weird because it is working fine in dev and all the other things works correct but it is just the upload part to s3 that I have issues with
Avatar
linesofcode
Wrap all of that in a try/catch
And log the error
Avatar
WatermanOP
the for (const... part?
Avatar
linesofcode
The contents of the POST function
Then deploy and open up the logs in vercel
And see what happens when you trigger it
Avatar
WatermanOP
is this correct?
import { NextRequest, NextResponse } from "next/server";
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { getServerSession } from "next-auth";
import { authOptions } from "../auth/[...nextauth]/route";

export const POST = async (req: NextRequest) => {
  try {
    const session = await getServerSession(authOptions);

    if (!session) {
      throw "Not Admin";
    }

    const formData = await req.formData();

    const client = new S3Client({
      region: "eu-north-1",
      credentials: {
        accessKeyId: process.env.S3_ACCESS_KEY || "",
        secretAccessKey: process.env.S3_SECRET_ACCESS_KEY || "",
      },
    });

    const links = [];

    for (const file of formData.getAll("file")) {
      const blob = file as Blob; // Assert that file is a Blob.
      const ext = blob.type?.split("/").pop();
      const newFileName = `${Date.now()}-${Math.random()
        .toString(36)
        .substring(2, 15)}.${ext}`;

      const fileBuffer = Buffer.from(await blob.arrayBuffer()); // Use Buffer.from to convert ArrayBuffer to Buffer.
      const fileUint8Array = new Uint8Array(fileBuffer);

      client.send(
        new PutObjectCommand({
          Bucket: "nextjsleflyxbuckle",
          Key: newFileName,
          Body: fileUint8Array,
          ACL: "public-read",
          ContentType: blob.type,
        })
      );
      const link = `https://nextjsleflyxbuckle.s3.eu-north-1.amazonaws.com/${newFileName}`;
      links.push(link);
    }
  } catch (er) {
    console.log(er);
  }

  return NextResponse.json({ links });
};
Avatar
linesofcode
(It may take a few seconds for logs to show up in vercel btw)
Avatar
WatermanOP
thank you alot for your time, I will try that and write what happend
Avatar
linesofcode
Also in case this helps you
Either as a drop in package or use the codebase to see examples of how to interact with s3
@Waterman I think I see the issue!!
client.send returns a promise
But you’re not awaiting for it
In a serverless environment like vercel
Avatar
WatermanOP
oh but does that explain why it doesn't work in prod but in dev
Avatar
linesofcode
Any promises which have not completed by the time your function returns an http response will be flushed
This means that when deploying to vercel, you need to await everything
Avatar
WatermanOP
oh right, I do not understand fully but I am very happy that you seemed to be understading it
Avatar
linesofcode
Otherwise you’re creating a race condition
Avatar
WatermanOP
could you maybe try giving an example or modify the code a little?
Avatar
linesofcode
In development this doesn’t happen because it’s not serverless
Avatar
WatermanOP
oh right, kinda makes sence
but is it an easy fix in the code?
Avatar
linesofcode
One sec..
Avatar
WatermanOP
yes thank you
Avatar
linesofcode
await       client.send(
        new PutObjectCommand({
          Bucket: "nextjsleflyxbuckle",
          Key: newFileName,
          Body: fileUint8Array,
          ACL: "public-read",
          ContentType: blob.type,
        })
      );
just add an await to wait for the promise to resolve
Avatar
WatermanOP
so all I need is an await??
oh really
I will try that thank you so much, one sec
Avatar
linesofcode
Yep
just be sure to remember this for the future
it's really nuanced and a lot of devs get tricked with this
when deploying to a serverless enviornment
so await all promises and you'll be good
Avatar
WatermanOP
I really didn't even know it was serverless haha
yeah becauase await have saved me a couple of times but when I wrote this s3 code I didn't understand what I did becauase I followed an old tutorial so thats prob the reason
Avatar
linesofcode
ah okay
Avatar
WatermanOP
it worked 😄
Avatar
linesofcode
awesome
Avatar
WatermanOP
Thank you so much, I have been struggling with this for 3 weeks
haha
so everytime when I made a new product for ecommerce website I had to run in dev etc
Avatar
linesofcode
😅
Answer
Avatar
WatermanOP
thank youy
Avatar
linesofcode
no problem, good luck!