dapr/dapr · critical

failed to parse default actor idle timeout: %s

Error message

failed to parse default actor idle timeout: %s

What it means

The actors runtime reads the default idle timeout as a string (cfg.DefaultIdleTimeout, sourced from the app's actor configuration served at /dapr/config, field actorIdleTimeout). It converts the string with Go's time.ParseDuration. If the string is not a valid Go duration, actors Init fails and the runtime stops. Valid values look like "1h", "30m", or "1h30m".

Source

Thrown at pkg/actors/actors.go:465

		}
	}

	drainOngoingCallTimeout := api.DefaultOngoingCallTimeout
	if len(cfg.DrainOngoingCallTimeout) > 0 {
		var err error
		drainOngoingCallTimeout, err = time.ParseDuration(cfg.DrainOngoingCallTimeout)
		if err != nil {
			return fmt.Errorf("failed to parse drain ongoing call timeout: %s", err)
		}
		drainOngoingCallTimeout = api.ClampDrainOngoingCallTimeout(drainOngoingCallTimeout, a.disseminationTimeout, "global config")
	}

	idleTimeout := api.DefaultIdleTimeout
	if len(cfg.DefaultIdleTimeout) > 0 {
		var err error
		idleTimeout, err = time.ParseDuration(cfg.DefaultIdleTimeout)
		if err != nil {
			return fmt.Errorf("failed to parse default actor idle timeout: %s", err)
		}
	}

	reentrancy := cfg.Reentrancy
	if reentrancy.MaxStackDepth == nil {
		reentrancy.MaxStackDepth = ptr.Of(api.DefaultReentrancyStackLimit)
	}

	factories := make([]table.ActorTypeFactory, 0, len(cfg.HostedActorTypes))
	for _, actorType := range cfg.HostedActorTypes {
		idleTimeout := idleTimeout
		reentrancy := reentrancy
		if c, ok := entityConfigs[actorType]; ok {
			idleTimeout = c.ActorIdleTimeout
			reentrancy = c.ReentrancyConfig
		}

		factories = append(factories, table.ActorTypeFactory{

View on GitHub (pinned to 74ad417027)

Solutions

  1. Set actorIdleTimeout to a valid Go duration string: "1h", "45m", or "1h30m".
  2. Use only the units ns, us, ms, s, m, h. No spaces, no days, no years.
  3. Omit the field to accept the default of 1h.
  4. Check drainOngoingCallTimeout and per-entity idle timeouts in the same config. They use the same parser and fail the same way.

Example fix

// before: app serves GET /dapr/config
{"entities":["MyActor"],"actorIdleTimeout":"1hour"}

// after
{"entities":["MyActor"],"actorIdleTimeout":"1h"}
Defensive patterns

Strategy: validation

Validate before calling

func validateActorConfig(idleTimeout, drainTimeout string) error {
	if idleTimeout != "" {
		if _, err := time.ParseDuration(idleTimeout); err != nil {
			return fmt.Errorf("invalid actorIdleTimeout %q: %w", idleTimeout, err)
		}
	}
	if drainTimeout != "" {
		if _, err := time.ParseDuration(drainTimeout); err != nil {
			return fmt.Errorf("invalid drainOngoingCallTimeout %q: %w", drainTimeout, err)
		}
	}
	return nil
}

Try / catch

Catch at runtime init and fail fast: if err := actorsRuntime.Init(ctx); err != nil && strings.Contains(err.Error(), "failed to parse default actor idle timeout") { log.Fatal("fix actorIdleTimeout in /dapr/config; use Go duration syntax like 1h") }. The value cannot be corrected at runtime.

Prevention

When it happens

Trigger: The app's /dapr/config response sets actorIdleTimeout (or an embedded runtime sets Config.DefaultIdleTimeout) to a string time.ParseDuration rejects: "1hour", "30 minutes", "1 h", "3600" (no unit), or an ISO-8601 value like "PT1H". Init returns this error before any actor type registers.

Common situations: A developer writes a human-readable unit in YAML or code. A value is copied from a system that uses ISO durations. An SDK sends a bare number. The same block also parses drainOngoingCallTimeout, so a typo in either field fails startup.

Understand the failure class

Related errors


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