{"record":{"id":"a9bce568e9f1e54f","repo":"dapr/dapr","slug":"timers-are-not-implemented","errorCode":null,"errorMessage":"timers are not implemented","messagePattern":"timers are not implemented","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/actors/targets/workflow/executor/executor.go","lineNumber":326,"sourceCode":"}\n\n// tryDeactivate requests deactivation without ever blocking the caller: the\n// deactivation queue is drained serially and each item waits on the actor's\n// wait group, which the caller is currently holding. If the queue is full the\n// actor simply stays in the table until HaltNonHosted or shutdown reaps it.\nfunc (e *executor) tryDeactivate() {\n\tselect {\n\tcase e.deactivateCh <- e:\n\tdefault:\n\t}\n}\n\nfunc (e *executor) InvokeReminder(ctx context.Context, reminder *actorapi.Reminder) error {\n\treturn errors.New(\"reminders are not implemented\")\n}\n\nfunc (e *executor) InvokeTimer(ctx context.Context, reminder *actorapi.Reminder) error {\n\treturn errors.New(\"timers are not implemented\")\n}\n\nfunc (e *executor) Deactivate(_ context.Context) error {\n\tif !e.closed.CompareAndSwap(false, true) {\n\t\treturn nil\n\t}\n\n\t// Close under mu so complete's closed-check-then-park cannot straddle\n\t// the close and strand a payload in a deactivated actor. wg.Wait stays\n\t// outside: in-flight invocations hold wg and may be waiting on mu.\n\te.mu.Lock()\n\tclose(e.closeCh)\n\te.table.Delete(e.actorID)\n\te.mu.Unlock()\n\te.wg.Wait()\n\treturn nil\n}\n","sourceCodeStart":308,"sourceCodeEnd":344,"githubUrl":"https://github.com/dapr/dapr/blob/74ad41702745709bb15fe2114ff693b8c59bc3cc/pkg/actors/targets/workflow/executor/executor.go#L308-L344","documentation":"The workflow executor internal actor implements InvokeTimer by returning errors.New(\"timers are not implemented\") (executor.go:325-327). Executor actors have no timer lifecycle: workflow timers are durable timers managed by the orchestrator via reminders. The error fires only if a timer is delivered to an executor actor, which means a timer was scheduled against an internal actor type or a misrouted scheduler entry.","triggerScenarios":"CreateTimer/scheduler timer delivery addressed to the workflow executor actor type; tooling that registers timers on every actor type including internal ones; scheduler state replay after upgrades.","commonSituations":"Enumerating actor types and scheduling timers programmatically; leftover scheduler entries from an older runtime; custom tooling driving internal actor APIs.","solutions":["Remove timers scheduled on dapr internal workflow actor types","Register timers only on your application actors","Purge scheduler entries that target internal actor types after upgrades","Align daprd versions so internal actor naming stays consistent"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// before registering a timer, ensure the target is an application actor\nif isInternalWorkflowActor(actorType) {\n    return errors.New(\"timers cannot target internal workflow actors\")\n}","typeGuard":"func isTimerNotImplemented(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"timers are not implemented\")\n}","tryCatchPattern":"if err := scheduler.RegisterTimer(ctx, actorType, id, t); err != nil {\n    if isTimerNotImplemented(err) {\n        return fmt.Errorf(\"timer routed to internal actor %q: target an app actor instead\", actorType)\n    }\n    return err\n}","preventionTips":["Register timers only on application actor types","Use workflow APIs (durable timers) for time-based workflow logic, not actor timers","Audit scheduler entries after runtime upgrades"],"tags":["workflow","actors","timers","misconfiguration"],"backgroundTag":null,"analyzedSha":"74ad41702745709bb15fe2114ff693b8c59bc3cc","analyzedAt":"2026-08-16T04:22:26.543Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}