VectifyAI/PageIndex · error · TypeError

user_opt must be dict, config(SimpleNamespace) or None

Error message

user_opt must be dict, config(SimpleNamespace) or None

What it means

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.

Source

Thrown at pageindex/utils.py:1095

    def _validate_keys(self, user_dict):
        unknown_keys = (set(user_dict) - set(self._default_dict)
                        - set(_MODEL_KEYS))
        if unknown_keys:
            raise ValueError(f"Unknown config keys: {unknown_keys}")

    def load(self, user_opt=None) -> config:
        """
        Load the configuration, merging user options with default values.
        """
        if user_opt is None:
            user_dict = {}
        elif isinstance(user_opt, config):
            user_dict = vars(user_opt)
        elif isinstance(user_opt, dict):
            user_dict = user_opt
        else:
            raise TypeError("user_opt must be dict, config(SimpleNamespace) or None")

        self._validate_keys(user_dict)
        merged = {**self._default_dict, **user_dict}
        _resolve_models(merged)
        return config(**merged)

def create_node_mapping(tree, include_page_ranges=False, max_page=None):
    """Map node_id to node; with include_page_ranges, to {"node", "start_index",
    "end_index"} (end = next node's page_index, or max_page for the last node)."""
    def get_all_nodes(tree):
        if isinstance(tree, dict):
            return [tree] + [node for child in tree.get('nodes', []) for node in get_all_nodes(child)]
        elif isinstance(tree, list):
            return [node for item in tree for node in get_all_nodes(item)]
        return []

    all_nodes = get_all_nodes(tree)
    if not include_page_ranges:

View on GitHub (pinned to afb5e11976)

Solutions

  1. Convert to a dict: vars(namespace), json.loads(s), or dataclasses.asdict(obj)
  2. Or construct/pass a pageindex config(SimpleNamespace) instance
  3. Pass None to use defaults

Example fix

# before
cfg = load(args)  # argparse.Namespace -> TypeError
# after
cfg = load(vars(args))
Defensive patterns

Strategy: type-guard

Validate before calling

assert user_opt is None or isinstance(user_opt, (dict, config)), \
    f'user_opt must be dict/config/None, got {type(user_opt).__name__}'
cfg = load(user_opt)

Type guard

from types import SimpleNamespace
from pageindex.utils import config

def is_loadable_opt(x) -> bool:
    return x is None or isinstance(x, (dict, config)) or (
        isinstance(x, SimpleNamespace) and type(x).__name__ == 'config')

Try / catch

try:
    cfg = load(user_opt)
except TypeError as e:
    if 'must be dict' in str(e):
        cfg = load(vars(user_opt))  # e.g. argparse.Namespace
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: Using argparse.Namespace directly, passing a config file path where a dict is expected, or deserializing JSON without json.loads first.

Related errors


AI-assisted analysis of VectifyAI/PageIndex@afb5e11976 (2026-08-27). Data as JSON: /api/errors/01acfb9a44389c03. Report an issue: GitHub.