{"record":{"id":"17e9380d5edda649","repo":"infiniflow/ragflow","slug":"param-define-nesting-too-deep-can-not-parse-it","errorCode":null,"errorMessage":"Param define nesting too deep!!!, can not parse it","messagePattern":"Param define nesting too deep!!!, can not parse it","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/component/base.py","lineNumber":149,"sourceCode":"\n            return ret_dict\n\n        return _recursive_convert_obj_to_dict(self)\n\n    def update(self, conf, allow_redundant=False):\n        update_from_raw_conf = conf.get(_IS_RAW_CONF, True)\n        if update_from_raw_conf:\n            deprecated_params_set = self._get_or_init_deprecated_params_set()\n            feeded_deprecated_params_set = self._get_or_init_feeded_deprecated_params_set()\n            user_feeded_params_set = self._get_or_init_user_feeded_params_set()\n            setattr(self, _IS_RAW_CONF, False)\n        else:\n            feeded_deprecated_params_set = self._get_or_init_feeded_deprecated_params_set(conf)\n            user_feeded_params_set = self._get_or_init_user_feeded_params_set(conf)\n\n        def _recursive_update_param(param, config, depth, prefix):\n            if depth > settings.PARAM_MAXDEPTH:\n                raise ValueError(\"Param define nesting too deep!!!, can not parse it\")\n\n            inst_variables = param.__dict__\n            redundant_attrs = []\n            for config_key, config_value in config.items():\n                # redundant attr\n                if config_key not in inst_variables:\n                    if not update_from_raw_conf and config_key.startswith(\"_\"):\n                        setattr(param, config_key, config_value)\n                    else:\n                        setattr(param, config_key, config_value)\n                        # redundant_attrs.append(config_key)\n                    continue\n\n                full_config_key = f\"{prefix}{config_key}\"\n\n                if update_from_raw_conf:\n                    # add user feeded params\n                    user_feeded_params_set.add(full_config_key)","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/agent/component/base.py#L131-L167","documentation":"Component parameters are applied by recursively walking nested param objects and config dicts. A depth counter guards against pathological/cyclic structures; exceeding settings.PARAM_MAXDEPTH aborts with this ValueError before recursion blows the stack.","triggerScenarios":"update()/load of a component config whose nesting depth exceeds settings.PARAM_MAXDEPTH — usually a config dict that (indirectly) contains itself, or a deeply nested legit structure from generated configs.","commonSituations":"Cyclic reference created by assigning a param object into its own sub-config; machine-generated configs with unbounded nesting; PARAM_MAXDEPTH lowered in settings; a config accidentally inlined multiple times (config containing a copy of the whole component including its config).","solutions":["Inspect the component config for cycles — most often a param dict that references an ancestor dict; break the cycle by deepcopying or restructuring.","Flatten unnecessarily deep structures; component params rarely need more than a few levels.","If a legitimate deep structure is required, raise settings.PARAM_MAXDEPTH deliberately (mind Python's recursion limit).","Log the config (json.dumps with default=repr) at the failure point to see the actual depth/shape."],"exampleFix":"# before\ncfg['parent'] = cfg  # self-reference -> infinite recursion\ncomponent.update(cfg)\n\n# after\nimport copy\ncfg['parent'] = copy.deepcopy(cfg_summary)  # acyclic, shallow\ncomponent.update(cfg)","handlingStrategy":"validation","validationCode":"def config_depth(conf):\n    if not isinstance(conf, dict):\n        return 0\n    return 1 + max((config_depth(v) for v in conf.values()), default=0)\n\ndef safe_update(component, conf, maxdepth):\n    if config_depth(conf) > maxdepth:\n        raise ValueError('config nesting exceeds PARAM_MAXDEPTH')\n    component.update(conf)","typeGuard":"def is_acyclic(conf):\n    seen = set()\n    stack = [conf]\n    while stack:\n        obj = stack.pop()\n        if id(obj) in seen:\n            return False\n        seen.add(id(obj))\n        if isinstance(obj, dict):\n            stack.extend(obj.values())\n        elif isinstance(obj, list):\n            stack.extend(obj)\n    return True","tryCatchPattern":"try:\n    component.update(conf)\nexcept ValueError as e:\n    if 'nesting too deep' in str(e):\n        conf = json.loads(json.dumps(conf, default=str))  # breaks cycles/normalizes\n        component.update(conf)","preventionTips":["Never insert a config dict into itself or its descendants.","Deep-copy configs sourced from shared objects before mutation.","Keep component configs shallow by design; deep structures belong in external refs."],"tags":["canvas","recursion","cyclic-config","parameter-validation"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}