Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[🐛 Bug]: "Failed to retrieve the Cloudflare request context" in app/api route handlers #683

Closed
1 task
thipperz opened this issue Feb 27, 2024 · 10 comments · Fixed by #702
Closed
1 task
Assignees
Labels
bug Something isn't working

Comments

@thipperz
Copy link

next-on-pages environment related information

System:
Platform: linux
Arch: x64
Version: #1 SMP Thu Oct 5 21:02:42 UTC 2023
CPU: (4) x64 AMD Ryzen 3 3200G with Radeon Vega Graphics
Memory: 8 GB
Shell: /bin/bash
Package Manager Used: pnpm (8.15.2)

Relevant Packages:
@cloudflare/next-on-pages: 1.9.0
vercel: N/A
next: 14.1.0

Description

Hi there,

I'm building a web app with Next-on-Pages.

I have a lib/db/data.ts file that exports a few functions that retrieve something from a D1 Database. This file looks like this:

export const runtime = 'edge'
import { cache } from 'react'
import { getRequestContext } from '@cloudflare/next-on-pages'
const { env } = getRequestContext()

async function getDatabase() {
    const database = env.CLOUDFLARE_DATABASE
    if (!database) {
        console.error('Database is not available')
        throw new Error('Database is not available')
    }
    return database
}

export const getUser = cache(async (id: number) => {
    const database = await getDatabase()

    try {
        const user = await database
            .prepare(
                `
                // query code
          `
            )
            .bind(id)
            .first()
        return user
    } catch (error) {
        throw new Error(`Error: ${error.message}`)
    }
})

Everything works fine when I import the getUser function in some route like app/user/page.tsx

However, if I were to import and use this function in the exact same way inside app/api/getUser/route.ts, the build will fail with a message like

                         ^

Error: Failed to retrieve the Cloudflare request context.
    at _ (..next/server/app/api/getUser/route.js:14:259)
    at 1838 (..next/server/app/api/getUser/route.js:1:1939)
    at __webpack_require__ (..next/server/edge-runtime-webpack.js:25:42)
    at 6295 (..next/server/app/api/getUser/route.js:1:573)
    at __webpack_require__ (..next/server/edge-runtime-webpack.js:25:42)
    at ..next/server/app/api/getUser/route.js:31:41915
    at webpackJsonpCallback (..next/server/edge-runtime-webpack.js:213:39)
    at ..next/server/app/api/getUser/route.js:1:51
    at Script.runInContext (node:vm:133:12)
    at runInContext (node:vm:287:6)

> Build error occurred
Error: Failed to collect page data for /api/getUser

All files (the api route handler, the page.tsx, and data.ts) have a export const runtime = 'edge' at the start.

Am I missing something?

Reproduction

No response

Pages Deployment Method

None

Pages Deployment ID

No response

Additional Information

No response

Would you like to help?

  • Would you like to help fixing this bug?
@thipperz thipperz added the bug Something isn't working label Feb 27, 2024
@thipperz
Copy link
Author

This was fixed by moving the getRequestContext() call to inside the function:

import { cache } from 'react'
import { getRequestContext } from '@cloudflare/next-on-pages'

async function getDatabase() {
    const { env } = getRequestContext()
    const database = env.CLOUDFLARE_DATABASE
    if (!database) {
        console.error('Database is not available')
        throw new Error('Database is not available')
    }
    return database
}

@dario-piotrowicz
Copy link
Member

Hi @thipperz, thanks for the issue 🙂

Sorry I haven't been able to reply to this sooner 🙇

I see that you've closed the issue and I'm glad you've found a workaround, but anyways your original code should work...
so I still feel like this issue's valid and that we need to investigate this further, I'm reopening the issue if that's ok with you 🙂

(PS: I'll try to investigate this soon but I don't know when I'll be able to 😓)

@dario-piotrowicz
Copy link
Member

Minimal reproduction for this issue: https://github.com/dario-piotrowicz/next-on-Pages-top-level-getRequestContext-bug-repro

Note

Everything works fine when I import the getUser function in some route like app/user/page.tsx

I don't get the above... as this bug/issue does seem to effect standard routes too (as you can see from my minimal reproduction) ¯\(ツ)

@dario-piotrowicz dario-piotrowicz self-assigned this Mar 10, 2024
@thipperz
Copy link
Author

thipperz commented Mar 11, 2024

I don't get the above... as this bug/issue does seem to effect standard routes too (as you can see from my minimal reproduction) ¯_(ツ)_/¯

Hi @dario-piotrowicz, I couldn't reproduce the issue again, perhaps I was mistaken as it was working with npm run dev. The build process indeed fails for both API and standard routes.

@treboryx
Copy link

I'm experiencing the same issue and I would rather not call getRequestContext on every route. This issue seems to have been introduced recently.

@dario-piotrowicz
Copy link
Member

Hi @dario-piotrowicz, I couldn't reproduce the issue again, perhaps I was mistaken as it was working with npm run dev. The build process indeed fails for both API and standard routes.

@thipperz thanks for the clarification 🙂 🙏

PS: I experimented with this and it seems like we'll have to go with your solution after all 😅
I'm documenting it properly cloudflare/cloudflare-docs#13371
and will make the error we throw in the build process user friendly trying to make this limitation as clear as possible for the user 🙂 (I wish we could do better but I don't think we can)

@dario-piotrowicz
Copy link
Member

I'm experiencing the same issue and I would rather not call getRequestContext on every route. This issue seems to have been introduced recently.

@treboryx the fact is that getRequestContext needs to be run as part of the request handling, calling it globally/unconditionally at the top level is something that we can't support (🥲) but if it's a problem for you
you can use global variables/memoization not to have to call it more than needed.

Also please keep in mind that getRequestContext is practically a getter, it doesn't really instantiate anything or anyways it doesn't have any costly operation so it's (in my opinion) really fine to call whenever you like.

@treboryx
Copy link

treboryx commented Mar 12, 2024

I'm experiencing the same issue and I would rather not call getRequestContext on every route. This issue seems to have been introduced recently.

@treboryx the fact is that getRequestContext needs to be run as part of the request handling, calling it globally/unconditionally at the top level is something that we can't support (🥲) but if it's a problem for you you can use global variables/memoization not to have to call it more than needed.

Also please keep in mind that getRequestContext is practically a getter, it doesn't really instantiate anything or anyways it doesn't have any costly operation so it's (in my opinion) really fine to call whenever you like.

Oh yeah I get that it's just that my code was nicely organized and now I have to use it everywhere.

HOWEVER, I found a solution that seems to work

import { getRequestContext } from "@cloudflare/next-on-pages";

const { env } = process.env.NODE_ENV === "development" ? getRequestContext() : process;

export const DB = env.DB;

export const STORAGE = env.STORAGE;

export const KV = env.KV;

I have to use getRequestContext in development but that doesn't seem to be the case when the application is deployed so I use process instead.

@dario-piotrowicz
Copy link
Member

@treboryx yeah.... that should indeed work 👍

Ideally I'd love it if people could not use process.env and just use getRequestContext (I am not a huge fan of having two different ways of doing the same thing) but I am not sure if we're ever going to actually remove the process.env bindings. Anyways that is not deprecated and it's unlikely to get deprecated (yet alone removed) any time soon, so your solution should be ok 🙂

Alternatively you could just use getOptionalRequestContext, that is totally fine to use in the top level (as soon as you do properly check the truthyness of the value that is).

So, could you maybe try:

import { getOptionalRequestContext } from "@cloudflare/next-on-pages";

const { env } = getOptionalRequestContext() ?? { env: {} };

that should pretty much be the exact same as your solution

@kit1211
Copy link

kit1211 commented Aug 21, 2024

in 2024, i still found this problem
i use chat gpt but i cant fix this error

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
4 participants