{"record":{"id":"01acfb9a44389c03","repo":"VectifyAI/PageIndex","slug":"user-opt-must-be-dict-config-simplenamespace-or","errorCode":null,"errorMessage":"user_opt must be dict, config(SimpleNamespace) or None","messagePattern":"user_opt must be dict, config\\(SimpleNamespace\\) or None","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"pageindex/utils.py","lineNumber":1095,"sourceCode":"\n    def _validate_keys(self, user_dict):\n        unknown_keys = (set(user_dict) - set(self._default_dict)\n                        - set(_MODEL_KEYS))\n        if unknown_keys:\n            raise ValueError(f\"Unknown config keys: {unknown_keys}\")\n\n    def load(self, user_opt=None) -> config:\n        \"\"\"\n        Load the configuration, merging user options with default values.\n        \"\"\"\n        if user_opt is None:\n            user_dict = {}\n        elif isinstance(user_opt, config):\n            user_dict = vars(user_opt)\n        elif isinstance(user_opt, dict):\n            user_dict = user_opt\n        else:\n            raise TypeError(\"user_opt must be dict, config(SimpleNamespace) or None\")\n\n        self._validate_keys(user_dict)\n        merged = {**self._default_dict, **user_dict}\n        _resolve_models(merged)\n        return config(**merged)\n\ndef create_node_mapping(tree, include_page_ranges=False, max_page=None):\n    \"\"\"Map node_id to node; with include_page_ranges, to {\"node\", \"start_index\",\n    \"end_index\"} (end = next node's page_index, or max_page for the last node).\"\"\"\n    def get_all_nodes(tree):\n        if isinstance(tree, dict):\n            return [tree] + [node for child in tree.get('nodes', []) for node in get_all_nodes(child)]\n        elif isinstance(tree, list):\n            return [node for item in tree for node in get_all_nodes(item)]\n        return []\n\n    all_nodes = get_all_nodes(tree)\n    if not include_page_ranges:","sourceCodeStart":1077,"sourceCodeEnd":1113,"githubUrl":"https://github.com/VectifyAI/PageIndex/blob/afb5e119766630af6014b04fe8b53357527bc05e/pageindex/utils.py#L1077-L1113","documentation":"config load accepts only None, a plain dict, or a config (SimpleNamespace) instance. Any other type — string, object with attributes, list — raises TypeError instead of guessing an attribute mapping.","triggerScenarios":"Passing something like an argparse.Namespace, a path string to a YAML file, a dataclass, or a JSON string to load()/page_index(config=...) instead of a dict/config/None.","commonSituations":"Using argparse.Namespace directly, passing a config file path where a dict is expected, or deserializing JSON without json.loads first.","solutions":["Convert to a dict: vars(namespace), json.loads(s), or dataclasses.asdict(obj)","Or construct/pass a pageindex config(SimpleNamespace) instance","Pass None to use defaults"],"exampleFix":"# before\ncfg = load(args)  # argparse.Namespace -> TypeError\n# after\ncfg = load(vars(args))","handlingStrategy":"type-guard","validationCode":"assert user_opt is None or isinstance(user_opt, (dict, config)), \\\n    f'user_opt must be dict/config/None, got {type(user_opt).__name__}'\ncfg = load(user_opt)","typeGuard":"from types import SimpleNamespace\nfrom pageindex.utils import config\n\ndef is_loadable_opt(x) -> bool:\n    return x is None or isinstance(x, (dict, config)) or (\n        isinstance(x, SimpleNamespace) and type(x).__name__ == 'config')","tryCatchPattern":"try:\n    cfg = load(user_opt)\nexcept TypeError as e:\n    if 'must be dict' in str(e):\n        cfg = load(vars(user_opt))  # e.g. argparse.Namespace\n    else:\n        raise","preventionTips":["Convert argparse.Namespace/dataclasses with vars()/asdict() at the boundary","Never pass file paths or JSON strings to load; parse first"],"tags":["config","typeerror","invalid-argument"],"backgroundTag":"invalid-config-type","analyzedSha":"afb5e119766630af6014b04fe8b53357527bc05e","analyzedAt":"2026-08-27T11:20:48.519Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}