Failed to parse body as FormData

Hello, when I push app to Vercel and upload the file I got an error. But if I use localhost url to upload the file - it works well

Server logs:

⨯ TypeError: Failed to parse body as FormData.
    at node:internal/deps/undici/undici:4249:27
    at successSteps (node:internal/deps/undici/undici:4288:27)
    at fullyReadBody (node:internal/deps/undici/undici:2724:9)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async consumeBody (node:internal/deps/undici/undici:4297:7)
    at async v (/var/task/.next/server/app/api/upload/route.js:6:9774)
    at async /var/task/node_modules/next/dist/compiled/next-server/app-route.runtime.prod.js:6:42484
    at async eI.execute (/var/task/node_modules/next/dist/compiled/next-server/app-route.runtime.prod.js:6:32486)
    at async eI.handle (/var/task/node_modules/next/dist/compiled/next-server/app-route.runtime.prod.js:6:43737)
    at async Y (/var/task/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:16:24600)

page.tsx:

import { Card } from '@/components/ui/card';
import { handleSubmit } from '@/actions';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';

const Page = () => {
	return (
		<Card className='p-3'>
			<form action={handleSubmit}>
				<Input type='file' name='files' />
				<Button type='submit' className='mt-10'>
					Submit
				</Button>
			</form>
		</Card>
	);
};

export default Page;

server action:

'use server';

export const handleSubmit = async (e: FormData) => {
	const response = await fetch('https://dvzh.tech/api/upload', {
		method: 'POST',
		body: e,
		headers: {
			'X-Upload-Folder': 'test',
		},
	});

	const data = await response.json();

	console.log('data', data);
};

src/app/api/upload/route.ts:

import { NextRequest, NextResponse } from 'next/server';
import { put } from '@vercel/blob';
import { nanoid } from 'nanoid';

export async function POST(request: NextRequest) {
	const folder = request.headers.get('X-Upload-Folder') || 'any';
	const uniqueName = nanoid(32);

	const form = await request.formData();
	const file = form.get('files') as File;
	const extension = file.name.split('.').pop();
	const fileName = `${uniqueName}.${extension}`;

	const blob = await put(`${folder}/${fileName}`, file, {
		access: 'public',
	});

	return NextResponse.json(blob, { status: 201 });

	// return await uploadFile(request, folder!);
}

also middleware:

import authConfig from '@/auth.config';
import NextAuth from 'next-auth';
import {
	API_ROUTES,
	authRoutes,
	DEFAULT_REDIRECT,
	publicApiRoutes,
	publicRoutes,
} from '@/routes';
import { NextResponse } from 'next/server';
export const { auth } = NextAuth(authConfig);

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
export default auth((req) => {
	const { nextUrl } = req;
	const isLoggedIn = !!req.auth;

	const requestHeaders = new Headers(req.headers);
	requestHeaders.set('x-url', nextUrl.pathname);
	requestHeaders.set('x-search', nextUrl.search);

	const isApiAuthRoute = nextUrl.pathname.startsWith(API_ROUTES.AUTH);
	const isPublicRoute = publicRoutes.includes(nextUrl.pathname);
	const isAuthRoute = authRoutes.includes(nextUrl.pathname);
	const isPublicApiRoute = (publicApiRoutes as string[]).includes(
		nextUrl.pathname,
	);

	// Allow public API routes
	if (isPublicApiRoute || isApiAuthRoute) {
		return null;
	}

	// Authentication pages
	if (isAuthRoute) {
		// The way to create an absolute url
		if (isLoggedIn) {
			return Response.redirect(new URL(DEFAULT_REDIRECT, nextUrl));
		}

		return null;
	}

	if (!isLoggedIn && !isPublicRoute) {
		// Redirect to previous page after login
		let callbackUrl = nextUrl.pathname;

		if (nextUrl.search) {
			callbackUrl += nextUrl.search;
		}

		const encodedCallbackUrl = encodeURIComponent(callbackUrl);

		return Response.redirect(
			new URL(`/auth/login?callbackUrl=${encodedCallbackUrl}`, nextUrl),
		);
	}

	return NextResponse.next({
		request: {
			headers: requestHeaders,
		},
	});
});

// Optionally, don't invoke Middleware on some paths
export const config = {
	matcher: [
		// Exclude files with a "." followed by an extension, which are typically static files.
		// Exclude files in the _next directory, which are Next.js internals.

		'/((?!.+\\.[\\w]+$|_next).*)',
		// Re-include any files in the api or trpc folders that might have an extension
		'/(api|trpc)(.*)',
	],
};

Hi @gokugoru!

I’m just following up here. It’s been a few days, did you manage to figure this out?

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.