alibaba/DataX · error · ValueError
tabular data doesn't appear to be a dict or a DataFrame
Error message
tabular data doesn't appear to be a dict or a DataFrame
What it means
ValueError from tabulate._format: the input has a keys()/values() shape (treated as dict-like) but neither callable .values() nor a usable .index attribute, so this old (0.7.x-era) tabulate cannot recognize it as a dict or a pandas DataFrame. It is a duck-typing heuristic failure against newer/custom mapping or DataFrame-like types.
Source
Thrown at otsstreamreader/tools/tabulate.py:699
is_headers2bool_broken = True
headers = list(headers)
index = None
if hasattr(tabular_data, "keys") and hasattr(tabular_data, "values"):
# dict-like and pandas.DataFrame?
if hasattr(tabular_data.values, "__call__"):
# likely a conventional dict
keys = tabular_data.keys()
rows = list(izip_longest(*tabular_data.values())) # columns have to be transposed
elif hasattr(tabular_data, "index"):
# values is a property, has .index => it's likely a pandas.DataFrame (pandas 0.11.0)
keys = tabular_data.keys()
vals = tabular_data.values # values matrix doesn't need to be transposed
# for DataFrames add an index per default
index = list(tabular_data.index)
rows = [list(row) for row in vals]
else:
raise ValueError("tabular data doesn't appear to be a dict or a DataFrame")
if headers == "keys":
headers = list(map(_text_type,keys)) # headers should be strings
else: # it's a usual an iterable of iterables, or a NumPy array
rows = list(tabular_data)
if (headers == "keys" and
hasattr(tabular_data, "dtype") and
getattr(tabular_data.dtype, "names")):
# numpy record array
headers = tabular_data.dtype.names
elif (headers == "keys"
and len(rows) > 0
and isinstance(rows[0], tuple)
and hasattr(rows[0], "_fields")):
# namedtuple
headers = list(map(_text_type, rows[0]._fields))View on GitHub (pinned to 80ec23d5c5)
Solutions
- Convert before calling: pass list(df.itertuples(index=False)) or [list(r) for r in df.values].
- Pass a plain dict {col: list_of_values} which the heuristic supports.
- Upgrade/replace the vendored tabulate with a current release that handles modern pandas.
Example fix
# before tabulate(df, headers='keys') # after tabulate([list(r) for r in df.itertuples(index=False)], headers=list(df.columns))
Defensive patterns
Strategy: type-guard
Validate before calling
if hasattr(tabular_data, 'keys') and not isinstance(tabular_data, dict):
tabular_data = list(tabular_data.values()) # or convert DataFrame rows explicitly Type guard
def is_supported_mapping(o):
return isinstance(o, dict) or (hasattr(o, 'values') and callable(o.values)) or hasattr(o, 'index') Prevention
- Normalize exotic inputs to list-of-lists or plain dict before calling this vendored tabulate.
- Keep the vendored tabulate version pinned and tested against your pandas version.
When it happens
Trigger: Passing a mapping-like object (has keys but .values is a property, e.g. modern pandas DataFrame normally has .index so fails earlier heuristics; or OrderedDict subclasses, or dict-like ORM results) that matches neither the 0.11-era DataFrame fingerprint nor a plain dict.
Common situations: Vendored old tabulate used with modern pandas/numpy versions whose APIs moved; passing dict_items, generators, or custom Mapping objects to the otsstreamreader tooling.
Related errors
- index must be as long as the number of data rows
- headers for a list of dicts is not a dict or a keyword
AI-assisted analysis of alibaba/DataX@80ec23d5c5 (2026-08-14).
Data as JSON: /api/errors/9bb51af5eaf384b6.
Report an issue: GitHub.