OpenBMB/ChatDev · error · ConfigError
duration_unit must be one of: {', '.join(valid_units)}
Error message
duration_unit must be one of: {', '.join(valid_units)} What it means
LoopTimerConfig.from_dict validates the optional 'duration_unit' (default 'seconds') against exactly ['seconds', 'minutes', 'hours']. Unlike input_mode, this check is case-sensitive with no normalization — str() is applied, so the raw spelling must match.
Source
Thrown at entity/configs/node/loop_timer.py:49
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,
reset_on_emit=reset_on_emit,
message=message,
passthrough=passthrough,
path=path,
)
def validate(self) -> None:View on GitHub (pinned to 4fb2db0ea9)
Solutions
- Use exactly 'seconds', 'minutes', or 'hours' (lowercase)
- Omit duration_unit to keep the 'seconds' default
- Normalize user input: unit.strip().lower() before building the dict, and map shorthand like 's'/'sec' to 'seconds'
Example fix
# before
{"max_duration": 5, "duration_unit": "Minutes"}
# after
{"max_duration": 5, "duration_unit": "minutes"} Defensive patterns
Strategy: type-guard
Validate before calling
UNITS = {'seconds', 'minutes', 'hours'}
u = str(data.get('duration_unit', 'seconds'))
if u not in UNITS:
data['duration_unit'] = 'seconds' Type guard
def unit_ok(data: dict) -> bool:
return str(data.get('duration_unit', 'seconds')) in {'seconds', 'minutes', 'hours'} Try / catch
try:
LoopTimerConfig.from_dict(data, path='lt')
except ConfigError as e:
if 'duration_unit' in e.path:
data['duration_unit'] = 'seconds'
LoopTimerConfig.from_dict(data, path='lt')
else:
raise Prevention
- Remember this check is case-sensitive, unlike input_mode
- Expose only the three allowed values in UIs
- Normalize shorthand ('s','min') to full words at the boundary
When it happens
Trigger: Passing duration_unit: 'Seconds' (capitalized), 's', 'min', 'm', 'day', or 'days'. Only the exact lowercase strings 'seconds', 'minutes', 'hours' pass.
Common situations: Assuming case-insensitivity like other fields in this library; using shorthand units from other config formats; typos.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- model.input_mode must be 'prompt' or 'messages'
- role must be 'user' or 'assistant'
- max_duration must be a number
- max_duration must be > 0
- model.name must be a non-empty string
AI-assisted analysis of OpenBMB/ChatDev@4fb2db0ea9 (2026-08-27).
Data as JSON: /api/errors/07259cab69503a97.
Report an issue: GitHub.