Skip to content

fix(testing): resolve async function configs in unstable_getResponseFromNextConfig#92514

Closed
sleitor wants to merge 1 commit into
vercel:canaryfrom
sleitor:fix-92500
Closed

fix(testing): resolve async function configs in unstable_getResponseFromNextConfig#92514
sleitor wants to merge 1 commit into
vercel:canaryfrom
sleitor:fix-92500

Conversation

@sleitor
Copy link
Copy Markdown
Contributor

@sleitor sleitor commented Apr 8, 2026

What?

Plugin wrappers like @sentry/nextjs, @vercel/workflow wrap the user config in an async function:

// next.config.mjs
function withPlugin(config) {
  return async (phase, { defaultConfig }) => ({ ...config })
}
export default withPlugin({ rewrites() { ... } })

When such a config is passed to unstable_getResponseFromNextConfig, the config is passed directly to loadCustomRoutes, which immediately accesses config.rewrites, config.redirects, etc. Since the value is still a function, all those properties are undefined and every route matcher returns null.

Why?

loadCustomRoutes expects a plain config object. The main Next.js config loader already calls normalizeConfig(phase, rawExport) which properly resolves both function and Promise exports before use.

How?

Call normalizeConfig(PHASE_PRODUCTION_BUILD, nextConfig) before passing to loadCustomRoutes. This is the same helper used by the Next.js config loading pipeline to unwrap function/async function configs.

Also broadened the TypeScript parameter type to accept function-wrapped configs without needing an as any cast in user code.

Test

Added two test cases in config-testing-utils.test.ts:

  1. Synchronous function config (phase, ctx) => config
  2. Async function config (plugin wrapper pattern) (phase, ctx) => Promise<config>

Closes #92500

…romNextConfig

Plugin wrappers like @sentry/nextjs wrap the user config in an async
function: `(phase, ctx) => config`. When such a config is passed to
`unstable_getResponseFromNextConfig`, `loadCustomRoutes` receives the
function instead of the resolved object and sees all route properties
as `undefined`, causing every matcher to return null.

Fix: call `normalizeConfig(PHASE_PRODUCTION_BUILD, nextConfig)` before
passing the result to `loadCustomRoutes`. This is the same helper used
by the main Next.js config loader to unwrap function and Promise exports.

Closes vercel#92500
@nextjs-bot
Copy link
Copy Markdown
Contributor

Allow CI Workflow Run

  • approve CI run for commit: 55b0be4

Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer

1 similar comment
@nextjs-bot
Copy link
Copy Markdown
Contributor

Allow CI Workflow Run

  • approve CI run for commit: 55b0be4

Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer

},
}) as any,
})
expect(response.status).toEqual(200)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Async function config test only asserts status 200 but not the rewrite URL, making it pass even if async config resolution is completely broken.

Fix on Vercel

@mischnic
Copy link
Copy Markdown
Member

mischnic commented Apr 8, 2026

Duplicate of #92501

@mischnic mischnic marked this as a duplicate of #92501 Apr 8, 2026
@mischnic mischnic closed this Apr 8, 2026
@sleitor sleitor deleted the fix-92500 branch April 8, 2026 14:45
@sleitor
Copy link
Copy Markdown
Contributor Author

sleitor commented Apr 8, 2026

@mischnic Thanks for pointing that out! You're right — #92501 (by @TooTallNate) addresses the same issue and was submitted first. Both use normalizeConfig but #92501 is a cleaner 4-line change. Happy to close this in favor of #92501 if that's the preferred path. Let me know!

@github-actions github-actions Bot locked as resolved and limited conversation to collaborators Apr 24, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

unstable_getResponseFromNextConfig does not resolve async function configs

3 participants