N
Nuxt2w ago
AGill

Uncaught Error: Disallowed operation called within global scope.

When deploying my Nuxt App to Cloudflare Workers I am starting to get this error: Uncaught Error: Disallowed operation called within global scope. Asynchronous I/O (ex: fetch() or connect()), setting a timeout, and generating random values are not allowed within global scope. To fix this error, perform this operation within a handler. https://developers.cloudflare.com/workers/runtime-apis/handlers/ Also get the error when doing a production preview on local machine. I am trying to use lazy components and lazy imports in some places but no luck. Full stack trace: ✘ [ERROR] service core:user:site-reporting-app: Uncaught Error: Disallowed operation called within global scope. Asynchronous I/O (ex: fetch() or connect()), setting a timeout, and generating random values are not allowed within global scope. To fix this error, perform this operation within a handler. https://developers.cloudflare.com/workers/runtime-apis/handlers/ at null.<anonymous> (index.js:78878:32) in Fo4 at null.<anonymous> (index.js:78899:86) at null.<anonymous> (index.js:78905:7) in .output/server/chunks/nitro/nitro.mjs at null.<anonymous> (index.js:5:59) in __init at null.<anonymous> (index.js:100286:1) ✘ [ERROR] The Workers runtime failed to start. There is likely additional logging output above. Any idea where to look?
Cloudflare Docs
Handlers
Methods, such as fetch(), on Workers that can receive and process external inputs.
12 Replies
kapa.ai
kapa.ai2w ago
Hi @AGill. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- This error comes from Cloudflare Workers’ restriction that you cannot run async operations (like fetch, timers, crypto-random, etc.) in the global scope of the worker; they must run inside a handler (the request/event handler). Cloudflare enforces this strictly and will refuse to start the worker when it detects such code. From the Nuxt side, there are a few relevant Cloudflare-related issues/fixes: - Nuxt has had to adjust behavior specifically for Cloudflare Workers multiple times (e.g. async layouts, using globalThis instead of window, and stricter handling of Workers’ environment). [async layouts; globalThis] - Cloudflare Workers are stricter than Node in other places too, such as DELETE requests through routeRules.proxy in Nuxt 4.2, where Workers will error immediately when a request pattern does not match its expectations, while Node “handles it gracefully”. [CF DELETE issue] However, in the knowledge sources there is no explicit example or fix for the exact "Disallowed operation called within global scope" error with Nuxt on Cloudflare. The stack trace you pasted (into nitro.mjs) suggests that some code path in your built server bundle is performing fetch/timer/random in the module top level (i.e. outside of a request handler), but the documents above do not show which pattern or config causes that. Because of that, I can only give general directions consistent with Cloudflare’s rules, not a precise line of code to change: 1. Check for top‑level async operations
Search your server-side code (server/, server/api/, server/plugins, nitro plugins, any custom entry files) for: - await fetch(...) / $fetch(...) - setTimeout, setInterval, setImmediate - crypto.getRandomValues, random token generation, etc.
that are executed at import time, e.g.:
// ❌ BAD for Workers: runs on module import
const result = await $fetch('/api/something')
export default defineEventHandler(() => result)

// ❌ BAD for Workers: runs on module import
const result = await $fetch('/api/something')
export default defineEventHandler(() => result)

Those must be moved into handler functions:
// ✅ OK: only runs per-request
export default defineEventHandler(async (event) => {
const result = await $fetch('/api/something')
return result
})

// ✅ OK: only runs per-request
export default defineEventHandler(async (event) => {
const result = await $fetch('/api/something')
return result
})

2. Look specifically at anything “lazy” that still runs at import time
The knowledge sources mention fixes around lazy-hydrated components and async data caching, but they’re about SSR behavior and don’t mention Cloudflare errors like yours. [lazy hydrated caching; pass slots to lazy hydrated]
So your use of <Lazy...> components is unlikely to be the direct cause; the real problem is probably a composable / plugin / server util doing async work when the module loads. 3. Be aware of Cloudflare’s stricter runtime vs Node
Similar to the DELETE proxy issue (works on Node server, fails on Workers), code that “seems fine” locally (Node dev server) can fail only on Cloudflare because of its global-scope restrictions. [CF DELETE issue]
If you see the same error in “production preview” locally, it likely means Nitro is running in a Cloudflare Worker-like preset (or simulating its constraints), exposing the same problem. 4. What the docs/PRs do not cover
None of the provided sources show: - a concrete example of this global-scope error with Nuxt on Cloudflare, - nor a Nuxt config flag that automatically rewrites such patterns.
So I can’t point to a specific Nuxt option as a fix based on these sources. Given the limitations of the knowledge sources, I can only say: - The error is due to async operations in global scope (very likely inside compiled Nitro server chunks). - To fix it you must refactor any such operations to run inside request handlers or lifecycle hooks, not at module import. - The Nuxt/Cloudflare issues we have documented show that Workers are stricter than Node, but they do not describe this exact stack trace or a ready-made Nuxt-side patch. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2w ago
<@508382519146709018> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
AGill
AGillOP2w ago
@kapa.ai Just to clarify, the .output folder has a public/ directory and a server/ directory. So the public/ directory has all my front end components and the server/ directory is all my server side code right? This would mean I can focus just on my server/ code and not the code contained in app/ directory right?
kapa.ai
kapa.ai2w ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Not quite. From the available sources, we only know this about the structure: - Nuxt builds into a .output/ directory produced by Nitro, which contains (at least) public/ and server/, plus nitro.json. [.output tip] - In the upcoming Nuxt 4 folder structure (which Nitro already understands when future.compatibilityVersion is enabled), the source folders look like this: [v4 folder structure]
.output/
.nuxt/
app/
assets/
components/
composables/
layouts/
middleware/
pages/
plugins/
utils/
app.vue
router.options.ts
modules/
node_modules/
public/
server/
api/
middleware/
plugins/
routes/
utils/
nuxt.config.ts

.output/
.nuxt/
app/
assets/
components/
composables/
layouts/
middleware/
pages/
plugins/
utils/
app.vue
router.options.ts
modules/
node_modules/
public/
server/
api/
middleware/
plugins/
routes/
utils/
nuxt.config.ts

From these docs we can infer: - app/ is your application source (components, pages, layouts, etc.). - server/ (at project root) is your Nitro server source (API routes, middleware, etc.). - public/ (at project root) is for static assets that are served as-is. [v4 folder structure] But the documents do not explicitly describe how .output/public and .output/server are organized internally or whether .output/public directly contains “all your front‑end components”. The .output layout is treated as a Nitro implementation detail, not a place you’re expected to develop in. [.output tip] So based on what we have: - It is not documented that .output/public holds your Vue components; rather, your components live in app/components (source), and the build output is an implementation detail. - You should not focus development inside .output/server or .output/public; instead, you work in app/ and server/, and Nitro/Nuxt generate .output/ for you. [v4 folder structure; .output tip] In other words: you still need to care about your app/ code (front end) and your server/ code (backend). The .output contents are build artifacts, not primary development targets. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2w ago
<@508382519146709018> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
AGill
AGillOP2w ago
@kapa.ai I was referring to what .output/ directory my front end components (in app/ directory) go to when doing a build.
kapa.ai
kapa.ai2w ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- In the provided sources, the .output/ directory is only described at a high level: - It’s the build output produced by Nitro, containing (at least) public/, server/, and nitro.json. [.output tip] - The source structure (when v4 compatibility is enabled) is: app/ for your application (components, pages, layouts, etc.) and server/ for Nitro server code. [v4 structure] However, the knowledge sources do not explicitly document how files from app/ are mapped into .output/—for example, they don’t say “components from app/components go to .output/public/_nuxt/...” or similar. The .output layout is treated as an internal build artifact, not something you’re expected to rely on structurally. [.output tip] So, based on what’s documented: - app/ is clearly your front‑end source directory. [v4 structure] - .output/ is the compiled result (client bundle + server bundle), but the exact per‑folder mapping of app/ into .output/ is not described in the provided materials. Because of that, I can’t state with confidence exactly which subdirectory of .output/ contains the compiled form of your app/ components, only that they end up as part of the build artifacts there. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2w ago
<@508382519146709018> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
AGill
AGillOP2w ago
Cool well likely in server/ code as mentioned earlier since the built file is nitro.mjs OK! So update on my end...... the offending package is @paralleldrive/cuid2 major version 3. Downgrading back to major version 2 resolves the issue... So the challenge for my is that I am using it in my drizzle/schema file and I have a top level import:
import { createId } from '@paralleldrive/cuid2';
import { createId } from '@paralleldrive/cuid2';
And I use the createId function for the default ids of my tables. @kapa.ai any suggestions?
kapa.ai
kapa.ai2w ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Cloudflare’s error is about what runs at module top level, not about ordinary imports themselves. From the sources we have: - Cloudflare Workers disallow async I/O, timers, and random value generation in global scope; those must run in a handler. This is exactly the error you’re seeing. - The Nuxt/Nitro sources don’t mention @paralleldrive/cuid2 specifically, nor show a documented pattern for fixing this package in Workers, so I can’t point to a Nuxt‑specific flag that fixes it automatically. Given that, and based on Cloudflare’s rules: - A plain import like:
import { createId } from '@paralleldrive/cuid2'

import { createId } from '@paralleldrive/cuid2'

is fine as long as the imported module does not itself call disallowed APIs at top level. - In your case, cuid2@3 is almost certainly doing something at module initialization that Cloudflare treats as “disallowed operation in global scope” (most likely using crypto/random at top level). Downgrading to v2 avoids that behavior, which matches your observation. What you can safely conclude from the docs: - There is no Nuxt‑side configuration in the provided sources that “wraps” such a library for Workers; the fix must come from: - changing the way the library is used (ensuring any call that generates IDs runs inside handlers, not at schema-definition time), and/or - using a version of the library that does not execute disallowed operations at module load. Because the knowledge sources don’t document cuid2 or Drizzle’s schema integration at all, I can’t provide a concrete, library‑specific code pattern from them—only the constraint: whatever creates the ID must not perform disallowed work when the worker module is imported. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2w ago
<@508382519146709018> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
AGill
AGillOP2w ago
Known issue that has been reported: https://github.com/paralleldrive/cuid2/issues/112
GitHub
Incompatibility issue in production build with cloudflare worker fr...
Description Hi there, thank you for the good work. During some maintenance update I discovered @paralleldrive/cuid2, starting from 3.0.1, cause crash in my production build, targeted Cloudflare wor...

Did you find this page helpful?