Used `params.locale`. `params` should be awaited before using its properties

Hello,

With Prismic and Next.js 15.x, I keep having this error in any dynamic route:

 Error: Route "/[locale]/freelancers/[uid]" used `params.locale`. `params` should be awaited before using its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis

Weirdly, I am already awaiting the params, but still not ok..:

import { SliceZone } from "@prismicio/react";
import type { Metadata } from "next";
import { getLocale } from "next-intl/server";
import { createClient } from "../../../../prismicio";
import { components } from "../../../../slices";

interface Params {
	uid: string;
}
export async function generateMetadata({
	params: _params,
}: {
	params: Promise<Params>;
}): Promise<Metadata> {
	const params = await _params;
	const locale = await getLocale();

	const client = createClient();
	// biome-ignore lint/suspicious/noImplicitAnyLet: <explanation>
	let page;

	try {
		page = await client.getByUID("page", params.uid, {
			lang: locale,
		});
	} catch (error) {
		console.error(
			`Failed to fetch page metadata for UID: ${params.uid}`,
			error,
		);
	}

	if (!page) {
		return {
			title: "Page not found",
			description: "The page you are looking for does not exist.",
		};
	}

	return {
		title: page.data.meta_title,
		description: page.data.meta_description,

		alternates: {
			canonical: `/${locale === "en" ? "" : `${locale}/`}${params.uid}`,
		},
		openGraph: {
			images: "/og-image.png",
			url: `${params.uid}`,
		},
	};
}

interface Props {
	params: Promise<Params>;
}

export default async function PageChild({ params: _params }: Props) {
	const params = await _params;
	// Validate UID - it should not include file extensions
	if (params.uid.match(/\.(png|jpg|jpeg|gif|ico|svg)$/)) {
		console.error(`Invalid UID: ${params.uid}`);
		return <div>Page not found</div>;
	}

	const client = createClient();

	// biome-ignore lint/suspicious/noImplicitAnyLet: <explanation>
	let page;

	try {
		page = await client.getByUID("page", params.uid, {
			lang: "*",
		});
	} catch (error) {
		console.error(
			`Failed to fetch page content for UID: ${params.uid}`,
			error,
		);
	}

	if (!page) {
		return <div>Page not found</div>;
	}

	return (
		<section className="mt-16 sm:mt-32">
			<SliceZone slices={page.data.slices} components={components} />
		</section>
	);
}

Or:

export async function generateMetadata(props: {
	params: Params;
	searchParams: SearchParams;
}) {
	const params = await props.params;
	const searchParams = await props.searchParams;
	const currentLocale = params.locale;
	const client = createClient();

	const t = await getTranslations("metas.freelancerPillarPage");
	const page = await client.getByUID("child_freelancer", params.uid, {
		lang: currentLocale,
	});

	const keyword = page.data.keyword || undefined;
	const currentPage = searchParams.page ? Number(searchParams.page) : 1;

	const dynamicTitle = keyword
		? t("titleWithKeyword", { keyword: capitalizeWords(keyword) })
		: page.data.meta_title || t("defaultTitle");

	const dynamicDescription = keyword
		? t("descriptionWithKeyword", { keyword: keyword.toLowerCase() })
		: page.data.meta_description || t("defaultDescription");

	const baseCanonical =
		params.locale === "en"
			? `/freelancers/${params.uid}`
			: `/${params.locale}/freelancers/${params.uid}`;

	const canonical =
		currentPage > 1
			? `${baseCanonical}?page=${currentPage}`
			: baseCanonical;

	return {
		title: dynamicTitle,
		description: dynamicDescription,
		alternates: {
			canonical: canonical,
		},
	};
}

export default async function FreelancerChildPage(props: {
	params: Params;
	searchParams: SearchParams;
}) {
	const params = await props.params;
	const searchParams = await props.searchParams;

	const client = createClient();
	const session = await getSession();
	const isCustomer = session?.user.userType === "CLIENT";

	const page = await client.getByUID("child_freelancer", params.uid, {
		lang: "*",
	});
	const keyword = page.data.keyword || undefined;
...

Thanks for the help!

Hey @Marving, thanks for reaching out to us!

This sounds weird, and your code reads fine to me. Given that you're working on an i18n website, could you double-check that elsewhere in your code, you're not also trying to read the page's params without awaiting them?

Maybe you have a component in the header, like a lang switcher or something, that is not part of this page, rather the layout technically, or a middleware somewhere before this that processes the route. I think the error would still look like it's thrown from the route in those cases too.

If not, could you try commenting the usage of params in your functions to attempt to pinpoint the issue or see if it goes away?

If none of those work, you could also try to provide us with a minimal reproduction, we're happy to having a look at your code :slight_smile:

Best, Lucie