run-llama/llama_index · error · TypeError

table_info must be a dictionary with table names as keys and

Error message

table_info must be a dictionary with table names as keys and the desired table info as values

What it means

The custom_table_info parameter of SQLDatabase/SQLWrapper must map table names to human-written table descriptions (a plain dict). Passing any non-dict (a JSON string, a list of pairs, a pandas object) raises TypeError at construction. Note the parameter is accepted as custom_table_info in the constructor and stored as _custom_table_info; the error text still says 'table_info'.

Source

Thrown at llama-index-core/llama_index/core/utilities/sql_wrapper.py:97

        if self._ignore_tables:
            missing_tables = self._ignore_tables - self._all_tables
            if missing_tables:
                raise ValueError(
                    f"ignore_tables {missing_tables} not found in database"
                )
        usable_tables = self.get_usable_table_names()
        self._usable_tables = set(usable_tables) if usable_tables else self._all_tables

        if not isinstance(sample_rows_in_table_info, int):
            raise TypeError("sample_rows_in_table_info must be an integer")

        self._sample_rows_in_table_info = sample_rows_in_table_info
        self._indexes_in_table_info = indexes_in_table_info

        self._custom_table_info = custom_table_info
        if self._custom_table_info:
            if not isinstance(self._custom_table_info, dict):
                raise TypeError(
                    "table_info must be a dictionary with table names as keys and the "
                    "desired table info as values"
                )
            # only keep the tables that are also present in the database
            intersection = set(self._custom_table_info).intersection(self._all_tables)
            self._custom_table_info = {
                table: info
                for table, info in self._custom_table_info.items()
                if table in intersection
            }

        self._max_string_length = max_string_length

        self._metadata = metadata or MetaData()
        # including view support if view_support = true
        self._metadata.reflect(
            views=view_support,
            bind=self._engine,

View on GitHub (pinned to afd0fef371)

Solutions

  1. Parse before passing: custom_table_info=json.loads(open('tables.json').read()).
  2. Build the dict literally: {'users': 'user accounts with roles', ...}.
  3. Remember keys are filtered to tables that exist in the DB, so use exact table names.

Example fix

# before
 db = SQLDatabase(engine, custom_table_info=raw_json_string)  # str -> TypeError

# after
 import json
 db = SQLDatabase(engine, custom_table_info=json.loads(raw_json_string))
Defensive patterns

Strategy: type-guard

Validate before calling

import json

def load_custom_table_info(raw) -> dict:
    if isinstance(raw, str):
        raw = json.loads(raw)  # accept JSON strings from config
    if not isinstance(raw, dict):
        raise TypeError('custom_table_info must be dict[str, str]')
    return raw

Type guard

def is_valid_custom_table_info(value) -> bool:
    return isinstance(value, dict) and all(isinstance(k, str) and isinstance(v, str) for k, v in value.items())

Try / catch

try:
    db = SQLDatabase(engine, custom_table_info=table_info)
except TypeError as e:
    if 'table_info must be a dictionary' in str(e) and isinstance(table_info, str):
        db = SQLDatabase(engine, custom_table_info=json.loads(table_info))
    else:
        raise

Prevention

When it happens

Trigger: SQLDatabase(engine, custom_table_info='{"users": "..."}') where the JSON string was never parsed; passing a list of (table, info) tuples; passing a single string containing formatted info for all tables.

Common situations: Loading table descriptions from a JSON file or env var and forgetting json.loads; older examples/docs that used a different shape for table info.

Related errors


AI-assisted analysis of run-llama/llama_index@afd0fef371 (2026-08-15). Data as JSON: /api/errors/7aab8536a80dce89. Report an issue: GitHub.