OpenBMB/ChatDev · error · ConfigError
recursive must be boolean
Error message
recursive must be boolean
What it means
FileSourceConfig.from_dict requires the optional 'recursive' flag (default True) to be an actual Python bool. Unlike many flags, no truthiness coercion is applied — 1/0, 'true', 'yes' all fail.
Source
Thrown at entity/configs/node/memory.py:117
@classmethod
def from_dict(cls, data: Mapping[str, Any], *, path: str) -> "FileSourceConfig":
mapping = require_mapping(data, path)
file_path = require_str(mapping, "path", path)
file_types_value = mapping.get("file_types")
file_types: List[str] | None = None
if file_types_value is not None:
items = ensure_list(file_types_value)
normalized: List[str] = []
for idx, item in enumerate(items):
if not isinstance(item, str):
raise ConfigError("file_types entries must be strings", extend_path(path, f"file_types[{idx}]") )
normalized.append(item)
file_types = normalized
recursive_value = mapping.get("recursive", True)
if not isinstance(recursive_value, bool):
raise ConfigError("recursive must be boolean", extend_path(path, "recursive"))
encoding = optional_str(mapping, "encoding", path) or "utf-8"
return cls(source_path=file_path, file_types=file_types, recursive=recursive_value, encoding=encoding, path=path)
FIELD_SPECS = {
"path": ConfigFieldSpec(
name="path",
display_name="File/Directory Path",
type_hint="str",
required=True,
description="Path to file/directory to be indexed",
),
"file_types": ConfigFieldSpec(
name="file_types",
display_name="File Type Filter",
type_hint="list[str]",
required=False,
description="List of file type suffixes to limit (e.g. .md, .txt)",View on GitHub (pinned to 4fb2db0ea9)
Solutions
- Use literal booleans: recursive: true (YAML) or "recursive": true (JSON)
- Convert strings explicitly before building the dict: recursive=str(v).lower() in ('1','true','yes')
- Parse booleans at the config boundary, not inside node configs
Example fix
# before
{"recursive": "false"}
# after
{"recursive": false} Defensive patterns
Strategy: validation
Validate before calling
r = cfg.get('recursive', True)
if not isinstance(r, bool):
cfg['recursive'] = str(r).strip().lower() in ('1', 'true', 'yes', 'on') Type guard
def recursive_is_bool(cfg: dict) -> bool:
r = cfg.get('recursive', True)
return r is None or isinstance(r, bool) Try / catch
try:
FileSourceConfig.from_dict(data, path='fs')
except ConfigError as e:
if 'recursive' in e.path:
data['recursive'] = str(data.get('recursive', True)).lower() in ('1', 'true', 'yes')
FileSourceConfig.from_dict(data, path='fs')
else:
raise Prevention
- Use literal true/false in YAML/JSON
- Parse string booleans at the config boundary
- Remember this field does NOT coerce truthiness
When it happens
Trigger: Passing recursive: 'true' (string), recursive: 1, or recursive: 'yes'. Only literal true/false booleans (YAML true/false, JSON true/false) pass.
Common situations: Env-var or query-string sourced values arriving as strings; formats that encode booleans as 0/1; assuming lenient coercion like bool() would provide.
Related errors
- memories must be a list
- file_types entries must be strings
- file_sources must contain at least one entry
- max_items must be a positive integer
- read must be boolean
AI-assisted analysis of OpenBMB/ChatDev@4fb2db0ea9 (2026-08-27).
Data as JSON: /api/errors/8884c5f52f0e0fa6.
Report an issue: GitHub.