dapr/dapr · error

timers are not implemented

Error message

timers are not implemented

What it means

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.

Source

Thrown at pkg/actors/targets/workflow/executor/executor.go:326

}

// tryDeactivate requests deactivation without ever blocking the caller: the
// deactivation queue is drained serially and each item waits on the actor's
// wait group, which the caller is currently holding. If the queue is full the
// actor simply stays in the table until HaltNonHosted or shutdown reaps it.
func (e *executor) tryDeactivate() {
	select {
	case e.deactivateCh <- e:
	default:
	}
}

func (e *executor) InvokeReminder(ctx context.Context, reminder *actorapi.Reminder) error {
	return errors.New("reminders are not implemented")
}

func (e *executor) InvokeTimer(ctx context.Context, reminder *actorapi.Reminder) error {
	return errors.New("timers are not implemented")
}

func (e *executor) Deactivate(_ context.Context) error {
	if !e.closed.CompareAndSwap(false, true) {
		return nil
	}

	// Close under mu so complete's closed-check-then-park cannot straddle
	// the close and strand a payload in a deactivated actor. wg.Wait stays
	// outside: in-flight invocations hold wg and may be waiting on mu.
	e.mu.Lock()
	close(e.closeCh)
	e.table.Delete(e.actorID)
	e.mu.Unlock()
	e.wg.Wait()
	return nil
}

View on GitHub (pinned to 74ad417027)

Solutions

  1. Remove timers scheduled on dapr internal workflow actor types
  2. Register timers only on your application actors
  3. Purge scheduler entries that target internal actor types after upgrades
  4. Align daprd versions so internal actor naming stays consistent
Defensive patterns

Strategy: validation

Validate before calling

// before registering a timer, ensure the target is an application actor
if isInternalWorkflowActor(actorType) {
    return errors.New("timers cannot target internal workflow actors")
}

Type guard

func isTimerNotImplemented(err error) bool {
    return err != nil && strings.Contains(err.Error(), "timers are not implemented")
}

Try / catch

if err := scheduler.RegisterTimer(ctx, actorType, id, t); err != nil {
    if isTimerNotImplemented(err) {
        return fmt.Errorf("timer routed to internal actor %q: target an app actor instead", actorType)
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: Enumerating actor types and scheduling timers programmatically; leftover scheduler entries from an older runtime; custom tooling driving internal actor APIs.

Related errors


AI-assisted analysis of dapr/dapr@74ad417027 (2026-08-16). Data as JSON: /api/errors/a9bce568e9f1e54f. Report an issue: GitHub.