vercel icon indicating copy to clipboard operation
vercel copied to clipboard

413 response body too large error could be more clear

Open leerob opened this issue 2 years ago • 6 comments

When I deploy a function that has a large response body (greater than 5mb):

import { readFileSync } from 'fs';
import path from 'path';

export default function handler(_, res) {
  const file = path.join(process.cwd(), 'large.mp3');
  const stringified = readFileSync(file, 'utf8');

  res.setHeader('Content-Type', 'application/json');
  return res.end(stringified);
}

I see a 500 error:

CleanShot 2022-06-15 at 20 23 52@2x

And the corresponding function log error:

CleanShot 2022-06-15 at 20 24 05@2x

This message:

LAMBDA_RUNTIME Failed to post handler success response. Http response code: 413.

Could more clearly state the reason it failed was due to the function response body size.

leerob avatar Jun 16 '22 01:06 leerob

Currently our team is facing the same problem...

It seemed to work just fine on Previews, however on Production, it's showing the same issue. There must be a way to handle this, our team had to switch to AWS Amplify because we were unable to locate the problem correctly

image

image

brian-enkor avatar Jun 17 '22 05:06 brian-enkor

There must be a way to handle this, our team had to switch to AWS Amplify because we were unable to locate the problem correctly

You'd have this same issue on AWS directly, since part of the limitation here is the maximum size imposed by Lambda.

It seemed to work just fine on Previews, however on Production, it's showing the same issue.

It's possible you likely have different request/response payloads in production. Could you share the code?

leerob avatar Jun 20 '22 00:06 leerob

Currently the it's happening when generating the main page,

const Home: FC<IRoomTabByType> = ({ dehydratedStateData }) => {
	const router = useRouter();

	const { isAuthenticated } = useAuth();
	const { openLoginModal, openResetPwModal } = useModal();
	const { mobile } = useWindowSize();

	const [showModal, setShowModal] = useState<boolean>(true);

	const {
		data: allAvailableRoomData,
		isFetching,
		error,
	} = useQuery(
		"getAvailableRooms",
		async () => {
			return await getRecommendRooms({ options: { limit: 20, page: 1 } });
		},
		{
			initialData: dehydratedStateData?.queries[0]?.state.data,
			retryOnMount: true,
			onError: function handleError(err: any) {
				return <div>{err}</div>;
			},
		},
	);

	const areaTab = (allAvailableRoomData?.areas as Pick<IHouse, "gu">[]) ?? [];

	const handleAuthModals = useCallback(
		async (modalname) => {
			try {
				await validate();
			} catch (e) {
				if (modalname === "login") {
					openLoginModal();
				} else if (modalname === "resetpw") {
					openResetPwModal();
				}
			}
		},
		[openLoginModal, openResetPwModal],
	);

	useEffect(() => {
		const { modal, message } = router.query;

		if (modal === "login" || modal === "resetpw") handleAuthModals(modal);

		if (message === "activate")
			ToastSuccess("Successfully verified your e-mail");
	}, [
		router,
		openLoginModal,
		openResetPwModal,
		isAuthenticated,
		handleAuthModals,
	]);

	const universityWithRoom = allAvailableRoomData?.univRoom?.universities;
	const data = allAvailableRoomData?.data ?? {
		count: 0,
		total: 0,
		rooms: [],
	};

	return (
		<main>
			<Layout
				isLogin={isAuthenticated}
				primaryHeader
				pageTitle="enkor Stay: Browse through houses in Seoul"
				fullWidth
				mobileTopMargin
				coloredBg
			>
				<HeadSection mobile={mobile} />
				<section className="overflow-x-hidden lg:overflow-hidden py-[64px] lg:py-[128px] lg:max-w-[1240px] lg:px-[60px] m-auto">
					<UniversitySection universityWithRoom={universityWithRoom} />
					<MiddleAdSection />
					<BannerSection />
					<HousingtypeSection areaTab={areaTab} allAvailableRoomData={data} />
				</section>
				<FooterSection />
			</Layout>
			<ErrorNotifyModal isOpen={showModal} setIsOpen={setShowModal} />
		</main>
	);
};

const getRecommendRooms = async ({ options }) => {
	const curPage = options.page;
	const [data, areas, universities, univRoom] = await Promise.all([
		getRooms({
			limit: options?.limit || ROOMS_PER_PAGE,
			offset: curPage,
			// livingType: options.livingType,
			// houseType: options.housingType,
			area: options.area,
			university: options.university,
		}),
		getAvailableAreas(),
		getAvailableUniversities(),
		getAllUniversityWithRoomCount(),
	]);

	return {
		limit: ROOMS_PER_PAGE,
		offset: curPage,
		data,
		areas,
		universities,
		univRoom,
	};
};

export const getStaticProps: GetStaticProps = async () => {
	const queryClient = new QueryClient();

	try {
		await queryClient.prefetchQuery("getAvailableRooms", () =>
			getRecommendRooms({ options: { limit: 20, page: 1 } }),
		);
		return {
			props: {
				dehydratedStateData: dehydrate(queryClient),
			},
			revalidate: 1,
		};
	} catch (error) {
		return {
			props: {},
		};
	}
};

export default Home;

brian-enkor avatar Jun 20 '22 00:06 brian-enkor

The page is using StaticProps as you can see, prefetching data from server and getting it down to the Home component which renders the main page of the website

brian-enkor avatar Jun 20 '22 00:06 brian-enkor

It's likely due to the size of dehydratedStateData returned from the server - can you try only returning the data inside there you need?

leerob avatar Jun 20 '22 01:06 leerob

Yes, actually looking into it, we figured it must have been due to the size of data returned from the server. We tried fetching data from the client-side without getStaticProps and it seems to work now!

This issue was hard to resolve due to ambiguous error message I guess.. sometimes we were looking into wrong places

brian-enkor avatar Jun 20 '22 01:06 brian-enkor