{"record":{"id":"ab933c958b54cfa9","repo":"can1357/oh-my-pi","slug":"tab-worker-entry-missing-parentport","errorCode":null,"errorMessage":"tab-worker-entry: missing parentPort","messagePattern":"tab-worker-entry: missing parentPort","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/browser/tab-worker-entry.ts","lineNumber":6,"sourceCode":"import { parentPort } from \"node:worker_threads\";\nimport { consumeWorkerInbox } from \"@oh-my-pi/pi-utils/worker-host\";\nimport type { Transport, WorkerInbound, WorkerOutbound } from \"./tab-protocol\";\nimport { WorkerCore } from \"./tab-worker\";\n\nif (!parentPort) throw new Error(\"tab-worker-entry: missing parentPort\");\n\nconst port = parentPort;\n// When the CLI host pre-buffered messages (it imports this module dynamically),\n// bind that inbox so the parent's already-delivered `init` is replayed. Loaded\n// directly (test/SDK fallback), this module's top-level runs synchronously at\n// worker start, so the direct `parentPort.on` below wins the flush on its own.\nconst inbox = consumeWorkerInbox();\nconst transport: Transport = {\n\tsend(msg, transferList) {\n\t\tport.postMessage(msg, transferList ?? []);\n\t},\n\tonMessage(handler) {\n\t\tif (inbox) return inbox.bind(data => handler(data as WorkerOutbound | WorkerInbound));\n\t\tconst wrap = (message: unknown): void => handler(message as WorkerOutbound | WorkerInbound);\n\t\tport.on(\"message\", wrap);\n\t\treturn () => port.off(\"message\", wrap);\n\t},\n\tclose() {","sourceCodeStart":1,"sourceCodeEnd":24,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/browser/tab-worker-entry.ts#L1-L24","documentation":"The tab worker entry module runs inside a Node worker thread and requires `parentPort` (the MessagePort to the parent process) to communicate. If the module is loaded outside a real `worker_threads` Worker context, `parentPort` is undefined and the module refuses to start.","triggerScenarios":"Importing `tab-worker-entry.ts` directly from the main thread, a test, or an SDK embedding instead of it being spawned as a `worker_threads` Worker; or the worker host spawns the script in a context where `parentPort` is null.","commonSituations":"A build/bundling mistake that changes the module graph so the entry is imported eagerly at startup; running under a runtime whose worker_threads shim doesn't provide parentPort; unit tests importing the entry file to inspect its exports.","solutions":["Ensure the entry is only ever launched via `new Worker(...)` (or the `workerHostEntry()` spawn path in cli.ts), never imported as a plain module.","If you must test the worker, spawn it as a real Worker in the test rather than importing the file.","Verify the worker argv selector (`__omp_worker_tab`) dispatch reaches this module only from the worker host entry path.","Check the runtime supports `node:worker_threads` with a non-null parentPort (plain `node`/`bun` workers do; bare `import` does not)."],"exampleFix":"// before (test)\nimport { WorkerCore } from \"./tab-worker-entry\";\n// after (test)\nconst worker = new Worker(new URL(\"./tab-worker-entry.ts\", import.meta.url), { type: \"module\" });","handlingStrategy":"validation","validationCode":"import { isMainThread } from \"node:worker_threads\";\nif (isMainThread) throw new Error(\"tab-worker-entry must run inside a Worker thread\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never import tab-worker-entry from main-thread code or tests","Spawn workers only via the workerHostEntry() spawn path","Test workers by spawning real Worker instances"],"tags":["worker-threads","worker","bootstrap","browser-tab"],"backgroundTag":"worker-parentport-missing","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}