{"record":{"id":"58dc3c817ed31090","repo":"OpenBMB/ChatDev","slug":"env-must-be-a-mapping","errorCode":null,"errorMessage":"env must be a mapping","messagePattern":"env must be a mapping","errorType":"validation","errorClass":"ConfigError","httpStatus":null,"severity":"error","filePath":"entity/configs/node/tooling.py","lineNumber":523,"sourceCode":"        mapping = require_mapping(data, path)\n        command = require_str(mapping, \"command\", path)\n        args_raw = ensure_list(mapping.get(\"args\"))\n        normalized_args: List[str] = []\n        for idx, arg in enumerate(args_raw):\n            arg_path = extend_path(path, f\"args[{idx}]\")\n            if not isinstance(arg, str):\n                raise ConfigError(\"args entries must be strings\", arg_path)\n            normalized_args.append(arg)\n\n        cwd = optional_str(mapping, \"cwd\", path)\n        inherit_env = optional_bool(mapping, \"inherit_env\", path, default=True)\n        if inherit_env is None:\n            inherit_env = True\n\n        env_mapping = mapping.get(\"env\")\n        if env_mapping is not None:\n            if not isinstance(env_mapping, Mapping):\n                raise ConfigError(\"env must be a mapping\", extend_path(path, \"env\"))\n            env = {str(k): str(v) for k, v in env_mapping.items()}\n        else:\n            env = {}\n\n        timeout_value = mapping.get(\"startup_timeout\", 10.0)\n        if timeout_value is None:\n            startup_timeout = 10.0\n        elif isinstance(timeout_value, (int, float)):\n            startup_timeout = float(timeout_value)\n        else:\n            raise ConfigError(\"startup_timeout must be numeric\", extend_path(path, \"startup_timeout\"))\n\n        wait_for_log = optional_str(mapping, \"wait_for_log\", path)\n        cache_ttl_value = mapping.get(\"cache_ttl\", 0.0)\n        if cache_ttl_value is None:\n            cache_ttl = 0.0\n        elif isinstance(cache_ttl_value, (int, float)):\n            cache_ttl = float(cache_ttl_value)","sourceCodeStart":505,"sourceCodeEnd":541,"githubUrl":"https://github.com/OpenBMB/ChatDev/blob/4fb2db0ea90375ce1059f44fe03ffbd191a7a169/entity/configs/node/tooling.py#L505-L541","documentation":"Raised when the stdio tooling config 'env' key exists but is not a mapping/dict. The env dict is normalized to str->str; any non-mapping (list, string, scalar) is rejected.","triggerScenarios":"env: [\"FOO=bar\"] (list of assignments) instead of env: {FOO: bar}; env: \"FOO=bar\" as a plain string; YAML indentation making env a list.","commonSituations":"Copying docker-run style -e FOO=bar syntax into the config; shell-style env strings not converted to dicts.","solutions":["Convert env to a mapping: env: {FOO: bar, BAZ: qux}","If your source is shell-style assignments, parse them into a dict first (dict(x.split('=',1) for x in pairs))","Remove env entirely to inherit/process-default to {}"],"exampleFix":"# before\nenv:\n  - FOO=bar\n# after\nenv:\n  FOO: bar","handlingStrategy":"type-guard","validationCode":"env = cfg.get(\"env\")\nassert env is None or isinstance(env, dict)","typeGuard":"from collections.abc import Mapping\ndef valid_env(v) -> bool:\n    return v is None or isinstance(v, Mapping)","tryCatchPattern":"except ConfigError as e:\n    if \"env must be a mapping\" in str(e):\n        cfg[\"env\"] = dict(x.split(\"=\", 1) for x in cfg[\"env\"])  # if list of K=V","preventionTips":["Store env as a YAML mapping, never a list of assignments","Convert docker-style -e K=V lists to dicts before parsing"],"tags":["config","validation","env","subprocess","tooling"],"backgroundTag":"config-type-validation-failed","analyzedSha":"4fb2db0ea90375ce1059f44fe03ffbd191a7a169","analyzedAt":"2026-08-27T14:35:29.622Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}