pydantic/monty · error · Error

nodeWorkerEntry must run as a worker thread

Error message

nodeWorkerEntry must run as a worker thread

What it means

`nodeWorkerEntry.ts` is the bootstrap script for a `worker_threads` backend worker. It reads `parentPort` to communicate with the parent thread, and if it is undefined the script is not actually running inside a Node worker thread. The module then aborts immediately because there is no message channel to serve dispatch requests on.

Source

Thrown at crates/monty-js/ts/worker/nodeWorkerEntry.ts:15

// Node `worker_threads` entry for a Monty worker.
//
// Runs in the worker thread and instantiates the precompiled component modules
// passed through `workerData`. `WebAssembly.Module`s are structured-cloneable,
// so each worker gets isolated state without recompiling. The browser entry
// provides the same transport over `self.postMessage`.

import { parentPort, workerData } from 'node:worker_threads'

import type { ComponentModules } from './host.js'
import { serveDispatch } from './serve.js'

void (async () => {
  const port = parentPort
  if (!port) throw new Error('nodeWorkerEntry must run as a worker thread')
  const { modules } = workerData as { modules: ComponentModules }
  await serveDispatch(
    modules,
    (reply) => port.postMessage(reply),
    (handler) => port.on('message', handler),
  )
})()

View on GitHub (pinned to adc986b362)

Solutions

  1. Run the worker via `new Worker(new URL('./nodeWorkerEntry.js', import.meta.url))` (or the library's `nodeFactory`) so Node creates a real `parentPort`.
  2. If wiring workers manually, pass `{ workerData: { modules } }` and only from code that itself runs inside a `Worker`, never on the main thread.
  3. Check bundler config: the worker entry must be emitted as a separate chunk, not inlined into the main bundle.

Example fix

// before
node ./dist/worker/nodeWorkerEntry.js   // main thread -> no parentPort

// after
import { Worker } from 'node:worker_threads'
const w = new Worker(new URL('./dist/worker/nodeWorkerEntry.js', import.meta.url), { workerData: { modules } })
Defensive patterns

Strategy: validation

Validate before calling

import { parentPort } from 'node:worker_threads'
if (!parentPort) throw new Error('nodeWorkerEntry must be launched inside a worker_threads Worker')

Type guard

function inWorkerThread(): boolean { return parentPort != null }

Try / catch

try {
  void bootstrap()
} catch (err) {
  console.error('worker bootstrap failed:', err)
  process.exitCode = 1
}

Prevention

When it happens

Trigger: Executing `nodeWorkerEntry.ts` (or the compiled `nodeWorkerEntry.js`) directly with `node`, or passing it as an entry to something that runs it on the main thread, so `parentPort` is undefined.

Common situations: Hand-wiring a `worker_threads.Worker` without a proper entry wrapper, misconfiguring a bundler so the worker entry is inlined into the main bundle, or debugging the worker file by running it standalone.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13). Data as JSON: /api/errors/1b13f77a73c6b93d. Report an issue: GitHub.