{"record":{"id":"8884c5f52f0e0fa6","repo":"OpenBMB/ChatDev","slug":"recursive-must-be-boolean","errorCode":null,"errorMessage":"recursive must be boolean","messagePattern":"recursive must be boolean","errorType":"validation","errorClass":"ConfigError","httpStatus":null,"severity":"error","filePath":"entity/configs/node/memory.py","lineNumber":117,"sourceCode":"\n    @classmethod\n    def from_dict(cls, data: Mapping[str, Any], *, path: str) -> \"FileSourceConfig\":\n        mapping = require_mapping(data, path)\n        file_path = require_str(mapping, \"path\", path)\n        file_types_value = mapping.get(\"file_types\")\n        file_types: List[str] | None = None\n        if file_types_value is not None:\n            items = ensure_list(file_types_value)\n            normalized: List[str] = []\n            for idx, item in enumerate(items):\n                if not isinstance(item, str):\n                    raise ConfigError(\"file_types entries must be strings\", extend_path(path, f\"file_types[{idx}]\") )\n                normalized.append(item)\n            file_types = normalized\n\n        recursive_value = mapping.get(\"recursive\", True)\n        if not isinstance(recursive_value, bool):\n            raise ConfigError(\"recursive must be boolean\", extend_path(path, \"recursive\"))\n\n        encoding = optional_str(mapping, \"encoding\", path) or \"utf-8\"\n        return cls(source_path=file_path, file_types=file_types, recursive=recursive_value, encoding=encoding, path=path)\n\n    FIELD_SPECS = {\n        \"path\": ConfigFieldSpec(\n            name=\"path\",\n            display_name=\"File/Directory Path\",\n            type_hint=\"str\",\n            required=True,\n            description=\"Path to file/directory to be indexed\",\n        ),\n        \"file_types\": ConfigFieldSpec(\n            name=\"file_types\",\n            display_name=\"File Type Filter\",\n            type_hint=\"list[str]\",\n            required=False,\n            description=\"List of file type suffixes to limit (e.g. .md, .txt)\",","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/OpenBMB/ChatDev/blob/4fb2db0ea90375ce1059f44fe03ffbd191a7a169/entity/configs/node/memory.py#L99-L135","documentation":"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.","triggerScenarios":"Passing recursive: 'true' (string), recursive: 1, or recursive: 'yes'. Only literal true/false booleans (YAML true/false, JSON true/false) pass.","commonSituations":"Env-var or query-string sourced values arriving as strings; formats that encode booleans as 0/1; assuming lenient coercion like bool() would provide.","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"],"exampleFix":"# before\n{\"recursive\": \"false\"}\n# after\n{\"recursive\": false}","handlingStrategy":"validation","validationCode":"r = cfg.get('recursive', True)\nif not isinstance(r, bool):\n    cfg['recursive'] = str(r).strip().lower() in ('1', 'true', 'yes', 'on')","typeGuard":"def recursive_is_bool(cfg: dict) -> bool:\n    r = cfg.get('recursive', True)\n    return r is None or isinstance(r, bool)","tryCatchPattern":"try:\n    FileSourceConfig.from_dict(data, path='fs')\nexcept ConfigError as e:\n    if 'recursive' in e.path:\n        data['recursive'] = str(data.get('recursive', True)).lower() in ('1', 'true', 'yes')\n        FileSourceConfig.from_dict(data, path='fs')\n    else:\n        raise","preventionTips":["Use literal true/false in YAML/JSON","Parse string booleans at the config boundary","Remember this field does NOT coerce truthiness"],"tags":["config","memory","boolean","validation","python"],"backgroundTag":"type-coercion-failed","analyzedSha":"4fb2db0ea90375ce1059f44fe03ffbd191a7a169","analyzedAt":"2026-08-27T14:35:29.622Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}