{"record":{"id":"7aab8536a80dce89","repo":"run-llama/llama_index","slug":"table-info-must-be-a-dictionary-with-table-names-a","errorCode":null,"errorMessage":"table_info must be a dictionary with table names as keys and the desired table info as values","messagePattern":"table_info must be a dictionary with table names as keys and the desired table info as values","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"llama-index-core/llama_index/core/utilities/sql_wrapper.py","lineNumber":97,"sourceCode":"        if self._ignore_tables:\n            missing_tables = self._ignore_tables - self._all_tables\n            if missing_tables:\n                raise ValueError(\n                    f\"ignore_tables {missing_tables} not found in database\"\n                )\n        usable_tables = self.get_usable_table_names()\n        self._usable_tables = set(usable_tables) if usable_tables else self._all_tables\n\n        if not isinstance(sample_rows_in_table_info, int):\n            raise TypeError(\"sample_rows_in_table_info must be an integer\")\n\n        self._sample_rows_in_table_info = sample_rows_in_table_info\n        self._indexes_in_table_info = indexes_in_table_info\n\n        self._custom_table_info = custom_table_info\n        if self._custom_table_info:\n            if not isinstance(self._custom_table_info, dict):\n                raise TypeError(\n                    \"table_info must be a dictionary with table names as keys and the \"\n                    \"desired table info as values\"\n                )\n            # only keep the tables that are also present in the database\n            intersection = set(self._custom_table_info).intersection(self._all_tables)\n            self._custom_table_info = {\n                table: info\n                for table, info in self._custom_table_info.items()\n                if table in intersection\n            }\n\n        self._max_string_length = max_string_length\n\n        self._metadata = metadata or MetaData()\n        # including view support if view_support = true\n        self._metadata.reflect(\n            views=view_support,\n            bind=self._engine,","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/run-llama/llama_index/blob/afd0fef371831f9bda13e5af7167cf4e981278ab/llama-index-core/llama_index/core/utilities/sql_wrapper.py#L79-L115","documentation":"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'.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\n db = SQLDatabase(engine, custom_table_info=raw_json_string)  # str -> TypeError\n\n# after\n import json\n db = SQLDatabase(engine, custom_table_info=json.loads(raw_json_string))","handlingStrategy":"type-guard","validationCode":"import json\n\ndef load_custom_table_info(raw) -> dict:\n    if isinstance(raw, str):\n        raw = json.loads(raw)  # accept JSON strings from config\n    if not isinstance(raw, dict):\n        raise TypeError('custom_table_info must be dict[str, str]')\n    return raw","typeGuard":"def is_valid_custom_table_info(value) -> bool:\n    return isinstance(value, dict) and all(isinstance(k, str) and isinstance(v, str) for k, v in value.items())","tryCatchPattern":"try:\n    db = SQLDatabase(engine, custom_table_info=table_info)\nexcept TypeError as e:\n    if 'table_info must be a dictionary' in str(e) and isinstance(table_info, str):\n        db = SQLDatabase(engine, custom_table_info=json.loads(table_info))\n    else:\n        raise","preventionTips":["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."],"tags":["sql","type-error","configuration","json"],"backgroundTag":null,"analyzedSha":"afd0fef371831f9bda13e5af7167cf4e981278ab","analyzedAt":"2026-08-15T05:42:58.429Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}