diff --git a/test/e2e/app-dir/instant-validation-build/app/(default)/pathname/invalid-use-pathname-deep-component/[one]/[two]/inner-wrapper.tsx b/test/e2e/app-dir/instant-validation-build/app/(default)/pathname/invalid-use-pathname-deep-component/[one]/[two]/inner-wrapper.tsx
new file mode 100644
index 000000000000..e8f065ce839f
--- /dev/null
+++ b/test/e2e/app-dir/instant-validation-build/app/(default)/pathname/invalid-use-pathname-deep-component/[one]/[two]/inner-wrapper.tsx
@@ -0,0 +1,11 @@
+'use client'
+
+import { PathnameReader } from './pathname-reader'
+
+export function InnerWrapper() {
+ return (
+
+ Current path:
+
+ )
+}
diff --git a/test/e2e/app-dir/instant-validation-build/app/(default)/pathname/invalid-use-pathname-deep-component/[one]/[two]/middle-wrapper.tsx b/test/e2e/app-dir/instant-validation-build/app/(default)/pathname/invalid-use-pathname-deep-component/[one]/[two]/middle-wrapper.tsx
new file mode 100644
index 000000000000..4c3c74fed751
--- /dev/null
+++ b/test/e2e/app-dir/instant-validation-build/app/(default)/pathname/invalid-use-pathname-deep-component/[one]/[two]/middle-wrapper.tsx
@@ -0,0 +1,11 @@
+'use client'
+
+import { InnerWrapper } from './inner-wrapper'
+
+export function MiddleWrapper() {
+ return (
+
+
+
+ )
+}
diff --git a/test/e2e/app-dir/instant-validation-build/app/(default)/pathname/invalid-use-pathname-deep-component/[one]/[two]/outer-wrapper.tsx b/test/e2e/app-dir/instant-validation-build/app/(default)/pathname/invalid-use-pathname-deep-component/[one]/[two]/outer-wrapper.tsx
new file mode 100644
index 000000000000..01dac3fbc9bd
--- /dev/null
+++ b/test/e2e/app-dir/instant-validation-build/app/(default)/pathname/invalid-use-pathname-deep-component/[one]/[two]/outer-wrapper.tsx
@@ -0,0 +1,11 @@
+'use client'
+
+import { MiddleWrapper } from './middle-wrapper'
+
+export function OuterWrapper() {
+ return (
+
+ )
+}
diff --git a/test/e2e/app-dir/instant-validation-build/app/(default)/pathname/invalid-use-pathname-deep-component/[one]/[two]/page.tsx b/test/e2e/app-dir/instant-validation-build/app/(default)/pathname/invalid-use-pathname-deep-component/[one]/[two]/page.tsx
new file mode 100644
index 000000000000..395f81e9d65e
--- /dev/null
+++ b/test/e2e/app-dir/instant-validation-build/app/(default)/pathname/invalid-use-pathname-deep-component/[one]/[two]/page.tsx
@@ -0,0 +1,26 @@
+import type { Instant } from 'next'
+import { OuterWrapper } from './outer-wrapper'
+
+export const unstable_instant: Instant = {
+ level: 'experimental-error',
+ unstable_samples: [
+ {
+ params: {
+ one: '123',
+ // two:
+ },
+ },
+ ],
+}
+
+export default function Page() {
+ return (
+
+
+ usePathname() nested three wrappers deep should still point at the
+ actual call site.
+
+
+
+ )
+}
diff --git a/test/e2e/app-dir/instant-validation-build/app/(default)/pathname/invalid-use-pathname-deep-component/[one]/[two]/pathname-reader.tsx b/test/e2e/app-dir/instant-validation-build/app/(default)/pathname/invalid-use-pathname-deep-component/[one]/[two]/pathname-reader.tsx
new file mode 100644
index 000000000000..c96d1a9f2b64
--- /dev/null
+++ b/test/e2e/app-dir/instant-validation-build/app/(default)/pathname/invalid-use-pathname-deep-component/[one]/[two]/pathname-reader.tsx
@@ -0,0 +1,8 @@
+'use client'
+
+import { usePathname } from 'next/navigation'
+
+export function PathnameReader() {
+ const pathname = usePathname()
+ return {pathname}
+}
diff --git a/test/e2e/app-dir/instant-validation-build/app/(default)/pathname/invalid-use-pathname-missing-params-no-wrapper/[one]/[two]/page.tsx b/test/e2e/app-dir/instant-validation-build/app/(default)/pathname/invalid-use-pathname-missing-params-no-wrapper/[one]/[two]/page.tsx
new file mode 100644
index 000000000000..337a29553479
--- /dev/null
+++ b/test/e2e/app-dir/instant-validation-build/app/(default)/pathname/invalid-use-pathname-missing-params-no-wrapper/[one]/[two]/page.tsx
@@ -0,0 +1,26 @@
+import type { Instant } from 'next'
+import { PathnameReader } from './pathname-reader'
+
+export const unstable_instant: Instant = {
+ level: 'experimental-error',
+ unstable_samples: [
+ {
+ params: {
+ one: '123',
+ // two:
+ },
+ },
+ ],
+}
+
+export default function Page() {
+ return (
+
+
+ usePathname() without an ensureThrows wrapper should point at the call
+ site in the user's source.
+
+
+
+ )
+}
diff --git a/test/e2e/app-dir/instant-validation-build/app/(default)/pathname/invalid-use-pathname-missing-params-no-wrapper/[one]/[two]/pathname-reader.tsx b/test/e2e/app-dir/instant-validation-build/app/(default)/pathname/invalid-use-pathname-missing-params-no-wrapper/[one]/[two]/pathname-reader.tsx
new file mode 100644
index 000000000000..c96d1a9f2b64
--- /dev/null
+++ b/test/e2e/app-dir/instant-validation-build/app/(default)/pathname/invalid-use-pathname-missing-params-no-wrapper/[one]/[two]/pathname-reader.tsx
@@ -0,0 +1,8 @@
+'use client'
+
+import { usePathname } from 'next/navigation'
+
+export function PathnameReader() {
+ const pathname = usePathname()
+ return {pathname}
+}
diff --git a/test/e2e/app-dir/instant-validation-build/instant-validation-build.test.ts b/test/e2e/app-dir/instant-validation-build/instant-validation-build.test.ts
index 7ebe14f6e75f..0168b2b5e7b5 100644
--- a/test/e2e/app-dir/instant-validation-build/instant-validation-build.test.ts
+++ b/test/e2e/app-dir/instant-validation-build/instant-validation-build.test.ts
@@ -816,6 +816,69 @@ describe('instant-validation-build', () => {
expect(result.cliOutput).not.toContain('AssertionError')
expect(result.exitCode).toBe(1)
})
+
+ it('error - usePathname() at the top of a Client Component body (no ensureThrows wrapper)', async () => {
+ const result = await prerender(
+ '/(default)/pathname/invalid-use-pathname-missing-params-no-wrapper/[one]/[two]'
+ )
+ // Today the function name is `` instead of `PathnameReader`.
+ expect(extractBuildValidationError(result.cliOutput))
+ .toMatchInlineSnapshot(`
+ "Error: Route "/pathname/invalid-use-pathname-missing-params-no-wrapper/[one]/[two]" called usePathname() but param "two" is not defined in the \`unstable_samples\` of \`unstable_instant\`. usePathname() requires all route params to be provided.
+ at (app/(default)/pathname/invalid-use-pathname-missing-params-no-wrapper/[one]/[two]/pathname-reader.tsx:6:20)
+ 4 |
+ 5 | export function PathnameReader() {
+ > 6 | const pathname = usePathname()
+ | ^
+ 7 | return {pathname}
+ 8 | }
+ 9 | {
+ digest: 'INSTANT_VALIDATION_ERROR'
+ }
+ Build-time instant validation failed for route "/pathname/invalid-use-pathname-missing-params-no-wrapper/[one]/[two]".
+ To get a more detailed stack trace and pinpoint the issue, try one of the following:
+ - Start the app in development mode by running \`next dev\`, then open "/pathname/invalid-use-pathname-missing-params-no-wrapper/[one]/[two]" in your browser to investigate the error.
+ - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
+ Stopping prerender due to instant validation errors."
+ `)
+ expect(result.cliOutput).not.toContain('AssertionError')
+ expect(result.exitCode).toBe(1)
+ })
+
+ it('error - usePathname() called from a Client Component nested three wrappers deep', async () => {
+ const result = await prerender(
+ '/(default)/pathname/invalid-use-pathname-deep-component/[one]/[two]'
+ )
+ // The minified function name is not deterministic, so normalize it.
+ const error = extractBuildValidationError(result.cliOutput).replace(
+ /at [a-z] \(app\/\(default\)/g,
+ 'at (app/(default)'
+ )
+ expect(error).toMatchInlineSnapshot(`
+ "Error: Route "/pathname/invalid-use-pathname-deep-component/[one]/[two]" called usePathname() but param "two" is not defined in the \`unstable_samples\` of \`unstable_instant\`. usePathname() requires all route params to be provided.
+ at (app/(default)/pathname/invalid-use-pathname-deep-component/[one]/[two]/pathname-reader.tsx:6:20)
+ 4 |
+ 5 | export function PathnameReader() {
+ > 6 | const pathname = usePathname()
+ | ^
+ 7 | return {pathname}
+ 8 | }
+ 9 | {
+ digest: 'INSTANT_VALIDATION_ERROR'
+ }
+ Build-time instant validation failed for route "/pathname/invalid-use-pathname-deep-component/[one]/[two]".
+ To get a more detailed stack trace and pinpoint the issue, try one of the following:
+ - Start the app in development mode by running \`next dev\`, then open "/pathname/invalid-use-pathname-deep-component/[one]/[two]" in your browser to investigate the error.
+ - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
+ Stopping prerender due to instant validation errors."
+ `)
+ const rawError = extractBuildValidationError(result.cliOutput)
+ expect(rawError).not.toContain('outer-wrapper.tsx')
+ expect(rawError).not.toContain('middle-wrapper.tsx')
+ expect(rawError).not.toContain('inner-wrapper.tsx')
+ expect(result.cliOutput).not.toContain('AssertionError')
+ expect(result.exitCode).toBe(1)
+ })
})
describe('root params', () => {