OpenBMB/ChatDev · error · ConfigError

max_duration must be > 0

Error message

max_duration must be > 0

What it means

LoopTimerConfig.from_dict rejects a max_duration that coerces to zero or a negative float. A timer that expires immediately or in the past is invalid.

Source

Thrown at entity/configs/node/loop_timer.py:42

    message: Optional[str] = None
    passthrough: bool = False

    @classmethod
    def from_dict(
        cls, data: Mapping[str, Any] | None, *, path: str
    ) -> "LoopTimerConfig":
        mapping = require_mapping(data or {}, path)
        max_duration_raw = mapping.get("max_duration", 60.0)
        try:
            max_duration = float(max_duration_raw)
        except (TypeError, ValueError) as exc:  # pragma: no cover - defensive
            raise ConfigError(
                "max_duration must be a number",
                extend_path(path, "max_duration"),
            ) from exc

        if max_duration <= 0:
            raise ConfigError(
                "max_duration must be > 0", extend_path(path, "max_duration")
            )

        duration_unit = str(mapping.get("duration_unit", "seconds"))
        valid_units = ["seconds", "minutes", "hours"]
        if duration_unit not in valid_units:
            raise ConfigError(
                f"duration_unit must be one of: {', '.join(valid_units)}",
                extend_path(path, "duration_unit"),
            )

        reset_on_emit = bool(mapping.get("reset_on_emit", True))
        message = optional_str(mapping, "message", path)
        passthrough = bool(mapping.get("passthrough", False))

        return cls(
            max_duration=max_duration,
            duration_unit=duration_unit,

View on GitHub (pinned to 4fb2db0ea9)

Solutions

  1. Use a positive duration, e.g. 60.0
  2. Pick the smallest sensible bound rather than 0 if you want a tight timeout
  3. To disable timing, remove the loop_timer node rather than zeroing the value

Example fix

# before
{"max_duration": 0}
# after
{"max_duration": 60.0}
Defensive patterns

Strategy: validation

Validate before calling

d = float(data.get('max_duration', 60.0))
if d <= 0:
    data['max_duration'] = 60.0

Type guard

def duration_positive(data: dict) -> bool:
    try:
        return float(data.get('max_duration', 60.0)) > 0
    except (TypeError, ValueError):
        return False

Try / catch

try:
    LoopTimerConfig.from_dict(data, path='lt')
except ConfigError as e:
    if '> 0' in str(e):
        data['max_duration'] = 60.0
        LoopTimerConfig.from_dict(data, path='lt')
    else:
        raise

Prevention

When it happens

Trigger: Passing max_duration: 0, negative numbers, or numeric strings like '0'/'-5'. Values in minutes/hours are still stored as raw numbers, so 0.5 seconds passes but 0 does not.

Common situations: Attempting to disable a timer with 0; arithmetic deriving duration that underflows to 0; unit confusion (entering 1 meaning 1 minute while intending 60 seconds still passes, but 0 never does).

Related errors


AI-assisted analysis of OpenBMB/ChatDev@4fb2db0ea9 (2026-08-27). Data as JSON: /api/errors/f9fdbc3fbc3c2077. Report an issue: GitHub.