{"record":{"id":"bf2b52c517f76c65","repo":"apache/beam","slug":"not-expecting-timers","errorCode":null,"errorMessage":"Not expecting timers.","messagePattern":"Not expecting timers\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"sdks/typescript/src/apache_beam/worker/operators.ts","lineNumber":244,"sourceCode":"            this_.lastProcessedElement += 1;\n            const maybePromise = this_.receiver.receive(\n              this_.coder.decode(reader, CoderContext.needsDelimiters),\n            );\n            if (maybePromise !== NonPromise) {\n              await maybePromise;\n            }\n            // Periodically yield control explicitly to allow other tasks\n            // (including splits requests) to get scheduled.\n            // Note that waiting on a resolved promise is not sufficient, so\n            // we do this in addition to the above loop.\n            if (Date.now() - lastYield > 100 /* milliseconds */) {\n              await new Promise((r) => setTimeout(r, 0));\n              lastYield = new Date().getTime();\n            }\n          }\n        },\n        sendTimers: async function (timerFamilyId: string, timers: Uint8Array) {\n          throw Error(\"Not expecting timers.\");\n        },\n        close: function () {\n          endOfDataResolve();\n        },\n        onError: function (error: Error) {\n          endOfDataReject(error);\n        },\n      },\n    );\n  }\n\n  process(wvalue: WindowedValue<unknown>): ProcessResult {\n    throw Error(\"Data should not come in via process.\");\n  }\n\n  split(\n    desiredSplit: fnApi.ProcessBundleSplitRequest_DesiredSplit,\n  ): fnApi.ProcessBundleSplitResponse_ChannelSplit | undefined {","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/typescript/src/apache_beam/worker/operators.ts#L226-L262","documentation":"The TypeScript worker's source/operator startBundle wires a sendTimers callback that unconditionally throws. This operator type does not expect timers to be emitted, so receiving them signals an internal invariant violation in bundle execution.","triggerScenarios":"During a bundle, the user transform (or windowing logic) emits a timer while running under this operator whose sendTimers is a throw-stub.","commonSituations":"Stateful/timer-using DoFns executed by the TypeScript worker; combining windowing features with an operator that doesn't support timer output; SDK feature gap.","solutions":["Avoid timers in transforms run by this operator; restructure to use windowing-only behavior.","Upgrade the apache-beam TypeScript SDK to a version supporting timers if available.","Move the timer-dependent transform to the Python or Java SDK."],"exampleFix":"// before\ncontext.setTimer(\"fire\", window, Duration.millis(0));\n// after\n// emit directly or rely on window triggers instead of timers","handlingStrategy":"validation","validationCode":"// assert transforms don't call setTimer before submitting to the TS worker\nif (transformRequiresTimers(dofn)) throw new Error(\"Refactor: timers unsupported here\");","typeGuard":null,"tryCatchPattern":"try {\n  await worker.startBundle();\n} catch (e) {\n  if (e.message === \"Not expecting timers.\") {\n    // redesign pipeline without timers or switch SDK\n  }\n}","preventionTips":["Avoid timer APIs in transforms executed by the TS worker.","Match runner and SDK versions to known-supported feature sets."],"tags":["typescript","beam","worker","timers","unsupported"],"backgroundTag":"unsupported-operation","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}