#V3, Vercel Blob Storage 400 error

35 messages · Page 1 of 1 (latest)

serene siren
#

Everything works as expected, but once the image is served through Next's image component I get a 400 error.

Interestingly though, it works fine in preview deployments.

In other words: mydemo.vercel.app shows a 400 error for images, while mydemo-grpvbmpkl-myteam.vercel.app shows the image as it should.

Tried updating my next.config.mjs, but it didn't do the trick:

import { withPayload } from '@payloadcms/next/withPayload'

/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    domains: ['mydemo.vercel.app'],
  },
}

export default withPayload(nextConfig)

My payload config is similar to https://github.com/payloadcms/vercel-deploy-payload-postgres/blob/main/src/payload.config.ts

GitHub

One-click deployment template of Payload 3.0 on Vercel - payloadcms/vercel-deploy-payload-postgres

balmy saddleBOT
ocean siren
#

Do you deploy with docker?

#

@serene siren

#

Ping me when you're back

serene siren
#

@ocean siren Nope! No docker.

ocean siren
#

Hmm

#

@serene siren What about specifying the dist directory on the image config?

serene siren
#

@ocean siren Hm, I'm using relative URLs because that's what the Payload API servers, so I'm guessing that's the issue. Would that mean that Next would technically be looking for the images at /public/api/images/file?

lament gazelle
#

@serene siren Did you ever solve this issue?

remote thorn
#

I'm currently facing it too

remote thorn
#

right! just figured it out if anyone else's having the same issue. thanks to @ocean siren for the above examples.

what you need to do is provide rewrites for your blob storage. (I was doing rewrites earlier today, but to make my relative path - absolute - and causing all sorts of issues);

in your next.config;

const nextConfig = { images: { remotePatterns: [ { protocol: 'https', hostname: '**.vercel-storage.com', }, ], }, async rewrites() { return [ { source: '/api/media/file/:filename*', destination: `${process.env.IMAGE_PROCESSOR_URL}/:filename*`, // https://[your-instance].public.blob.vercel-storage.com }, ] }, }

green sedge
#

you are a genius blud

grim sierra
#

I'm having the same issue but with docker/hetzner. Any idea? @solid sparrow ? (sorry I saw you asking about Docker)

solid sparrow
#

Hello hello

#

Hmm I'll have to read through this a bit

#

@grim sierra What does your next config look like currently?

#

I'm working on a C# project rn but happy to switch gears if you're really stuck xD

grim sierra
#
import createNextIntlPlugin from 'next-intl/plugin'

const withNextIntl = createNextIntlPlugin()

import redirects from './redirects.js'

/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'standalone',
  // Your Next.js config here
  images: {
    remotePatterns: [
      {
        protocol: 'http',
        hostname: 'localhost',
        port: '3000',
      },
      {
        protocol: 'https',
        hostname: 'tera.unset.studio',
      },
      {
        protocol: 'https',
        hostname: 'tera.porto.pt',
      },
    ],
  },
  async rewrites() {
    return [
      {
        source: '/api/media/file/:filename*',
        destination: `${process.env.NEXT_PUBLIC_SERVER_URL}/:filename*`,
      },
    ]
  },
  reactStrictMode: true,
  redirects,
}

export default withNextIntl(withPayload(nextConfig))
#

returning a 404 now

solid sparrow
#

The first pattern is just for local right?

grim sierra
#

y

solid sparrow
#

I would start by making that dev only to make sure it's not interfering, IDK if it necessary but I omit it

#

Also, are your images really served directly from root?

#

${process.env.NEXT_PUBLIC_SERVER_URL}/:filename*

#

Also, in your docker config, can we check out what you're mounting?

#

Hmm, I just checked and the local pattern shouldn't interfere, that's good

grim sierra
#
services:
  payload:
    build:
      context: .
      dockerfile: Dockerfile.prod
    ports:
      - '127.0.0.1:3000:3000' # Only bind to localhost for nginx proxy
    volumes:
      - ./media:/app/media # For uploaded files
      - ./emails:/app/emails # For email templates
      - ./.env:/app/.env
    working_dir: /app
    restart: unless-stopped
    environment:
      NODE_ENV: production
      DATABASE_URI: ${DATABASE_URI}
      PAYLOAD_SECRET: ${PAYLOAD_SECRET}
      PAYLOAD_PUBLIC_SERVER_URL: ${PAYLOAD_PUBLIC_SERVER_URL}
      NEXT_PUBLIC_SERVER_URL: ${NEXT_PUBLIC_SERVER_URL}
    depends_on:
      postgres:
        condition: service_healthy
    healthcheck:
      test: ['CMD', 'wget', '--quiet', '--tries=1', '--spider', 'http://localhost:3000/admin']
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ['CMD', 'pg_isready', '-U', 'postgres', '-d', 'tera']
      interval: 5s
      timeout: 5s
      retries: 5
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
      POSTGRES_DB: tera

volumes:
  pgdata:
#

actually yeah, files are served on /media

grim sierra
#

I'm using next-intl but I've ecluded /media on the middleware.ts