Skip to content

🧭 Solving the Console.createTask uncaught error in Cloudflare Workers when using React Email in development mode.

Notifications You must be signed in to change notification settings

niquenen/workerd-uncaught-error-console-createtask

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

14 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Solving the Console.createTask Uncaught Error in Cloudflare Workers

If you've been working with Cloudflare Workers and React (especially with libraries like React Emails), you may have encountered an error that stops your project from starting.

Uncaught Error: The Console.createTask method is not implemented
Table of contents

πŸš€ Get started

Prerequisites

  • Node.js (v20 or higher recommended)
  • npm or your preferred package manager

Installation

Clone this repository and install dependencies:

npm install

Running

To reproduce the error (before applying the fix), run the development server:

npm run dev

This runs cross-env NODE_ENV=development wrangler dev, which starts the local Cloudflare Workers development server and will trigger the error.

πŸ“– Understanding the Cloudflare Workers stack

Before diving into the error, it's helpful to understand the environment where this issue occurs.

What is workerd?

workerd is Cloudflare's open-source JavaScript/Wasm runtime that powers Cloudflare Workers. workerd is designed specifically for running JavaScript applications at the edge with the following characteristics:

  • Server-first design: Unlike general-purpose runtimes (Node.js, Deno), workerd is optimized specifically for HTTP servers and event-driven applications
  • Web standard APIs: Implements browser-compatible APIs (Fetch, WebCrypto, Streams) for better portability
  • Nanoservices model: Multiple Workers run in separate V8 isolates within a single process, providing isolation with minimal overhead
  • Capability bindings: Applications receive explicit access to specific resources (KV, R2, D1) rather than unrestricted network access, providing built-in SSRF protection

What is Wrangler?

Wrangler is Cloudflare's official CLI tool for developing, testing, and deploying Workers applications. It provides:

  • Local development server using the workerd runtime
  • Build tooling with esbuild for bundling TypeScript/JSX
  • Deployment to Cloudflare's edge network
  • Configuration management via wrangler.toml

Project structure

This project uses the standard Cloudflare Workers structure.

wrangler.toml

The configuration file that defines how your Worker runs:

name = "workerd-uncaught-error-console-createtask"
main = "./src/index.tsx"
compatibility_date = "2025-11-17"
compatibility_flags = [
  "nodejs_compat",
  "remove_nodejs_compat_eol"
]

Key configuration options:

  • name: Your Worker's identifier
  • main: Entry point for your application
  • compatibility_date: Locks runtime behavior to a specific date, ensuring consistent behavior
  • compatibility_flags: Fine-grained control over runtime features
    • nodejs_compat: Enables Node.js compatibility APIs
    • remove_nodejs_compat_eol: Removes deprecated end-of-life Node.js compatibility

index.tsx

Your Worker's entry point, which exports a fetch handler:

export default {
  async fetch(request: Request): Promise<Response> {
    // Your application logic
  }
}

How it all works together

  1. Development: wrangler dev starts a local workerd instance
  2. Bundling: Wrangler uses esbuild to bundle your TypeScript/JSX code
  3. Execution: workerd runs your bundled code in V8

πŸ› The issue

When running your Cloudflare Worker in development mode with NODE_ENV=development, you might see an error like this:

$ cross-env NODE_ENV=development wrangler dev

 ⛅️ wrangler 4.60.0
───────────────────
βŽ” Starting local server...
✘ [ERROR] service core:user:workerd-uncaught-error-console-createtask: Uncaught Error: The Console.createTask method is not implemented

    at null.<anonymous> (node:console:82:11) in createTask
    at null.<anonymous> (index.js:1620:35)
    at null.<anonymous> (index.js:2049:7) in node_modules/react/cjs/react.development.js
    at null.<anonymous> (index.js:12:50) in __require
    at null.<anonymous> (index.js:2063:24) in node_modules/react/index.js
    at null.<anonymous> (index.js:12:50) in __require
    at null.<anonymous> (index.js:29417:28)



✘ [ERROR] The Workers runtime failed to start. There is likely additional logging output above.


If you think this is a bug then please create an issue at https://github.com/cloudflare/workers-sdk/issues/new/choose
? Would you like to report this error to Cloudflare? Wrangler's output and the error details will be shared with the Wrangler team to help us diagnose and fix the issue.
πŸ€– Using fallback value in non-interactive context: no
πŸͺ΅  Logs were written to "/Users/niquenen/Library/Preferences/.wrangler/logs/wrangler-2026-01-26_08-36-03_290.log"
error: script "dev" exited with code 1

This error is particularly confusing because it only happens in development mode, the production builds work perfectly fine. Let's dig into why this happens and how to fix it.

Debugging journey

Step 0: Initial research

When facing an obscure error, the first step is always to search for existing solutions. I found only one discussion on Google:

This didn't provide a complete solution. Time to dig deeper.

Step 1: Verify it's development-only

First, I confirmed that production builds work fine:

# Production build - works fine
npx cross-env NODE_ENV=production wrangler dev

# $ cross-env NODE_ENV=production wrangler dev
#
#  ⛅️ wrangler 4.60.0
# ───────────────────
# βŽ” Starting local server...
# [wrangler:info] Ready on http://localhost:8787
# βŽ” Reloading local server...
# βŽ” Local server updated and ready

# Development build - fails
npx cross-env NODE_ENV=development wrangler dev

This isolated the issue to something specific to the development bundle. When NODE_ENV=development, different code paths are used.

Step 2: analyze the build

I used a custom esbuild command to analyze what was being bundled:

# Note: Conditions ("--conditions") were investigated in step 4
npx esbuild ./src/index.tsx \
  --bundle \
  --tsconfig=tsconfig.json \
  --format=esm \
  --platform=node \
  --conditions=workerd,worker,node \
  --outfile=dist/index.js \
  "--external:cloudflare:*" \
  --analyze=verbose 1&> build.txt

Looking at build.txt, I could see the React development files being included:

β”œ node_modules/react/cjs/react.development.js ──────────────────────────────── 20.3kb ─── 2.1%
β”‚  β”” node_modules/react/index.js
β”‚     β”” node_modules/react/cjs/react-jsx-runtime.development.js
β”‚        β”” node_modules/react/jsx-runtime.js
β”‚           β”” src/index.tsx
β”‚
β”‚
β”‚  [...]
β”‚
β”‚
β”œ node_modules/react-dom/cjs/react-dom.development.js ───────────────────────── 9.0kb ─── 0.9%
β”‚  β”” node_modules/react-dom/index.js
β”‚     β”” node_modules/react-dom/cjs/react-dom-server-legacy.browser.development.js
β”‚        β”” node_modules/react-dom/server.edge.js
β”‚           β”” node_modules/@react-email/render/dist/edge/index.mjs
β”‚              β”” node_modules/@react-email/components/dist/index.mjs
β”‚                 β”” src/index.tsx

Opening the bundled dist/index.js, I found browser-specific code:

  • __REACT_DEVTOOLS_GLOBAL_HOOK__ (React DevTools integration)
  • Multiple references to console.createTask()

This may confirmed a problem: browser APIs were being included in a server-side bundle. Is this normal?

Step 3: Search for Console.createTask references in React DOM

I searched the React DOM source files in node_modules/react-dom and found 4 results:

4 results - 2 files

cjs/react-dom-client.development.js:
  25627        now = Scheduler.unstable_now,
  25628:       createTask = console.createTask
  25629:         ? console.createTask
  25630          : function () {

cjs/react-dom-profiling.development.js:
  25679        now = Scheduler.unstable_now,
  25680:       createTask = console.createTask
  25681:         ? console.createTask
  25682          : function () {

Looking at the actual code in react-dom.development.js:

// #react-dom-client.development.js:25628
createTask = console.createTask
  ? console.createTask
  : function () {
      return null;
    },

The code is the same in React with the same search and 16 results:

// #react.development.js:695
createTask = console.createTask
  ? console.createTask
  : function () {
      return null;
    };

At first glance, this looks safe - React checks if console.createTask exists before using it. So why does it fail?

Step 4: Try custom build conditions

I suspected that @react-email/render, react or react-dom might be using the wrong package.json β€œexports” during the build phase.

Looking at @react-email/render's package.json, it defines multiple export conditions:

{
  "exports": {
    ".": {
      "workerd": {
        /* ... */
      },
      /* ... */
      "browser": {
        /* ... */
      },
      "default": {
        /* ... */
      }
    }
  }
}

I dove into Wrangler's source code to understand how it configures esbuild. Looking at bundle.ts:

// workers-sdk/packages/wrangler/src/deployment-bundle/bundle.ts#L67
export function getBuildConditions() {
  const envVar = getBuildConditionsFromEnv();
  if (envVar !== undefined) {
    return envVar.split(",");
  } else {
    return ["workerd", "worker", "browser"];
  }
}

The default conditions for esbuild are workerd, worker, and browser. The browser condition might be causing the issue by pulling in browser-specific code.

Wrangler supports environment variables to override build configuration. These variables are defined in factory.ts:

type VariableNames =
  | /* ... */
  /** Comma-separated list of build conditions for esbuild. */
  | "WRANGLER_BUILD_CONDITIONS"
  /** Build platform for esbuild (e.g., "node", "browser"). */
  | "WRANGLER_BUILD_PLATFORM"

The getBuildConditionsFromEnv() function reads the WRANGLER_BUILD_CONDITIONS variable:

// workers-sdk/packages/workers-utils/src/environment-variables/misc-variables.ts#L235
export const getBuildConditionsFromEnv = getEnvironmentVariableFactory({
  variableName: "WRANGLER_BUILD_CONDITIONS",
});

The OpenNext troubleshooting guide also mentions these variables for fixing npm package compatibility issues.

I tried overriding the build conditions:

npx cross-env NODE_ENV=development \
  WRANGLER_BUILD_CONDITIONS=workerd,worker,node \
  WRANGLER_BUILD_PLATFORM=node \
  wrangler dev

The server still failed to start. The issue was deeper than build configuration.

Step 5: Try a polyfill

A polyfill is code that provides functionality in environments that don't natively support it. I attempted to create one for console.createTask to provide a fallback:

// src/polyfill.ts
if (typeof (console as any).createTask !== 'function') {
  (console as any).createTask = function() { return null; };
}

And imported it at the top of the entry file:

// src/index.tsx
import './polyfill.ts';
// ...

This didn't work. The error persisted. As Cloudflare explains in their blog post More NPM packages on Cloudflare Workers:

Since these Node.js APIs are built directly into the Workers runtime, they can be written in C++, which allows them to be faster than JavaScript polyfills.

[...]

For some Node.js APIs, there is not yet native support in the Workers runtime nor a polyfill implementation. In these cases, unenv β€œmocks” the interface. This means it adds the module and its methods to your Worker, but calling methods of the module will either do nothing or will throw an error with a message like:

Some Node.js APIs (like buffer) are implemented natively in workerd with C++. For APIs that aren't implemented natively, unenv provides mocks as a fallback.

Step 6: Reading the workerd source code

At this point, I realized the problem was internal to the workerd runtime itself. Time to read the source code.

I opened the workerd repository and searched for createTask(). I found this in console.ts:

// workerd/src/node/console.ts#L103
export function createTask(): void {
  throw new ERR_METHOD_NOT_IMPLEMENTED('Console.createTask');
}
// @ts-expect-error TS2339 This is intentional.
globalConsole.createTask = createTask;
Console.prototype.createTask = createTask;

Aha! The workerd runtime intentionally defines console.createTask as a function that throws an internal error, rather than leaving it undefined.

import { ERR_METHOD_NOT_IMPLEMENTED } from 'node-internal:internal_errors';

This explains everything:

  1. React checks: console.createTask ? console.createTask : <fallback>
  2. Since console.createTask exists (as a function), the check evaluates to true
  3. React tries to call it
  4. workerd throws ERR_METHOD_NOT_IMPLEMENTED

πŸ“ The comment

There's even a comment in the workerd source acknowledging this issue:

// TODO(soon): This class is Node.js compatible but globalThis.console is not.
// This is because globalThis.console is provided by the v8 runtime.
// We need to find a way to patch and add createTask and context methods whenever
// `enable_nodejs_console_module` flag is enabled.

πŸ” Finding the solution

Remembering the article A year of improving Node.js compatibility in Cloudflare Workers, I remembered that Cloudflare allows you to enable or disable Node.js features individually using compatibility flags.

This led me to the solution: the disable_nodejs_console_module flag.

βœ”οΈ Resolves the issue

After all this investigation, the solution turns out to be surprisingly simple. Cloudflare provides a compatibility flag specifically for this situation.

Add the compatibility flag

Update your wrangler.toml to include the disable_nodejs_console_module flag:

# wrangler.toml
compatibility_flags = [
  "nodejs_compat",
  "remove_nodejs_compat_eol",
  "disable_nodejs_console_module"
]

The disable_nodejs_console_module flag tells workerd to not polyfill, this means console.createTask will be undefined instead of a throwing function, allowing React's fallback code to work correctly.

Why this works

With this flag enabled:

  • The node:console module is disabled
  • console.createTask is undefined instead of a throwing function
  • React's check console.createTask ? ... : fallback properly uses the fallback
  • Your development server starts successfully

Conclusion

If you encounter similar issues with other Node.js modules in Cloudflare Workers, remember to check the compatibility flags documentation for options to enable or disable specific features. You can also explore the Cloudflare Datamining workerd Compatibility Flags, a community project that list all flags automatically from the workerd source code.


This article documents a real debugging session at H2V Solutions. We hope it saves you time if you encounter the same issue!

About

🧭 Solving the Console.createTask uncaught error in Cloudflare Workers when using React Email in development mode.

Topics

Resources

Stars

Watchers

Forks