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
- Parse before passing: custom_table_info=json.loads(open('tables.json').read()).
- Build the dict literally: {'users': 'user accounts with roles', ...}.
- 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
- json.loads() any string-loaded table descriptions before constructing SQLDatabase.
- Type the config field as dict[str, str] in your settings model.
- Use exact table names as keys - unknown keys are silently filtered out.
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
- sample_rows_in_table_info must be an integer
- Must provide sql_database
- No async database URI or engine provided, cannot initialize
- embed_model must start with str 'local' or of type BaseEmbed
- Must pass in cohere api key or specify via COHERE_API_KEY en
AI-assisted analysis of run-llama/llama_index@afd0fef371 (2026-08-15).
Data as JSON: /api/errors/7aab8536a80dce89.
Report an issue: GitHub.