{"record":{"id":"962a0536603e2bb8","repo":"apache/beam","slug":"attempted-to-invoke-timer-timerid-on-classname-but-that","errorCode":null,"errorMessage":"Attempted to invoke timer ${timerId} on ${className}, but that timer is not registered. This is the responsibility of the runner, which must only deliver registered timers.","messagePattern":"Attempted to invoke timer (.+?) on (.+?), but that timer is not registered\\. This is the responsibility of the runner, which must only deliver registered timers\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/reflect/ByteBuddyDoFnInvokerFactory.java","lineNumber":326,"sourceCode":"     */\n    void addOnTimerFamilyInvoker(String timerFamilyId, OnTimerInvoker onTimerInvoker) {\n      this.onTimerFamilyInvokers.put(timerFamilyId, onTimerInvoker);\n    }\n\n    @Override\n    public void invokeOnTimer(\n        String timerId,\n        String timerFamilyId,\n        DoFnInvoker.ArgumentProvider<InputT, OutputT> arguments) {\n      @Nullable OnTimerInvoker onTimerInvoker =\n          timerFamilyId.isEmpty()\n              ? onTimerInvokers.get(timerId)\n              : onTimerFamilyInvokers.get(timerFamilyId);\n\n      if (onTimerInvoker != null) {\n        onTimerInvoker.invokeOnTimer(arguments);\n      } else {\n        throw new IllegalArgumentException(\n            String.format(\n                \"Attempted to invoke timer %s on %s, but that timer is not registered.\"\n                    + \" This is the responsibility of the runner, which must only deliver\"\n                    + \" registered timers.\",\n                timerId, delegate.getClass().getName()));\n      }\n    }\n\n    @Override\n    public DoFn<InputT, OutputT> getFn() {\n      return delegate;\n    }\n  }\n\n  /** Returns the {@link DoFnInvoker} for the given {@link DoFn}. */\n  public <InputT, OutputT> DoFnInvoker<InputT, OutputT> newByteBuddyInvoker(\n      DoFnSignature signature, DoFn<InputT, OutputT> fn) {\n    checkArgument(","sourceCodeStart":308,"sourceCodeEnd":344,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/reflect/ByteBuddyDoFnInvokerFactory.java#L308-L344","documentation":"DoFnInvoker dispatches @OnTimer callbacks by timer id through generated ByteBuddy invokers. This error is thrown when a runner delivers a timer that the DoFn never declared via @TimerId/@TimerFamily, so the invoker map has no handler for that timerId or timerFamilyId.","triggerScenarios":"A runner delivers a timer to a DoFn whose signature has no matching @TimerId (or @TimerFamily) field; timer ids drift between the job graph and the worker's copy of the code.","commonSituations":"Renaming a @TimerId field without redeploying so the staged graph and worker code disagree; a custom/direct runner bug delivering timers for the wrong DoFn; runner/SDK version mismatch.","solutions":["Check that every fired timer corresponds to a declared @TimerId field with a matching @OnTimer method in the DoFn.","Rebuild and redeploy so the pipeline graph and worker code use identical DoFn definitions.","If you own the runner, validate timer ids against DoFnSignatures before delivery and deliver only registered timers."],"exampleFix":"// before\n@ProcessElement public void process(...) { timer.set(...); } // no @TimerId declared\n// after\nclass MyFn extends DoFn<KV<String,Long>, Long> {\n  @TimerId public final TimerSpec timer = TimerSpecs.timer();\n  @ProcessElement public void process(...) { timer.set(...); }\n  @OnTimer(\"timer\") public void onTimer(...) { ... }\n}","handlingStrategy":"try-catch","validationCode":"DoFnSignature sig = DoFnSignatures.getSignature(fn.getClass());\nif (!sig.timerDeclarations().containsKey(timerId) && !sig.timerFamilyDeclarations().containsKey(timerFamilyId)) {\n  throw new IllegalArgumentException(\"timer not registered on \" + fn.getClass());\n}","typeGuard":null,"tryCatchPattern":"try {\n  invoker.invokeOnTimer(arguments);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"timer is not registered\")) {\n    throw new IllegalStateException(\"graph/worker mismatch: timer \" + timerId + \" missing on \" + fn.getClass(), e);\n  }\n  throw e;\n}","preventionTips":["Declare every timer with @TimerId (or @TimerFamily) and match @OnTimer ids exactly.","Rebuild and redeploy the whole pipeline after renaming timer fields so graph and worker agree.","Custom runners should validate timer ids against DoFnSignatures before delivering."],"tags":["java","apache-beam","runner","timer","dofn"],"backgroundTag":"invalid-state-transition","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}