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

  1. Use literal booleans: recursive: true (YAML) or "recursive": true (JSON)
  2. Convert strings explicitly before building the dict: recursive=str(v).lower() in ('1','true','yes')
  3. 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

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


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