getredash/redash · error · Exception
Missing `columns` field in `result` dict.
Error message
Missing `columns` field in `result` dict.
What it means
Raised by PythonQueryRunner.validate_result (redash/query_runner/python.py:325) when the script's `result` dict exists and has `rows` but is missing the `columns` key. Redash requires both keys to build a result table; columns drives the table headers and column ordering in the UI.
Source
Thrown at redash/query_runner/python.py:325
return user
def test_connection(self):
pass
def validate_result(self, result):
"""Validate the result after executing the query.
Parameters:
:result dict: The result dict.
"""
if not result:
raise Exception("local variable `result` should not be empty.")
if not isinstance(result, dict):
raise Exception("local variable `result` should be of type `dict`.")
if "rows" not in result:
raise Exception("Missing `rows` field in `result` dict.")
if "columns" not in result:
raise Exception("Missing `columns` field in `result` dict.")
if not isinstance(result["rows"], list):
raise Exception("`rows` field should be of type `list`.")
if not isinstance(result["columns"], list):
raise Exception("`columns` field should be of type `list`.")
def run_query(self, query, user):
self._current_user = user
try:
error = None
code = compile_restricted(query, "<string>", "exec")
builtins = safe_builtins.copy()
builtins["_write_"] = self.custom_write
builtins["__import__"] = self.custom_import
builtins["_getattr_"] = safer_getattr
builtins["getattr"] = safer_getattrView on GitHub (pinned to ca79fe988d)
Solutions
- Add `columns` as a list of column metadata dicts, typically `[{'name': ..., 'friendly_name': ..., 'type': ...}]`
- Keep `columns` names consistent with the keys used in each row dict
- Order `columns` in the display order you want in the Redash table
Example fix
# before
result = {'rows': [{'id': 1}]}
# after
result = {'columns': [{'name': 'id', 'friendly_name': 'ID', 'type': 'integer'}], 'rows': [{'id': 1}]} Defensive patterns
Strategy: validation
Validate before calling
missing = [k for k in ('rows', 'columns') if k not in result]
if missing:
raise ValueError('result dict missing: {}'.format(missing)) Type guard
def has_required_keys(r: dict) -> bool:
return isinstance(r, dict) and all(k in r for k in ('rows', 'columns')) Try / catch
try:
validate_result(result)
except Exception as e:
return None, 'Invalid result shape: {}'.format(e) Prevention
- Always construct result in one literal with both keys
- Derive columns from the same source as rows so they cannot diverge
- Add a unit check in CI for shared Python query snippets
When it happens
Trigger: A Python query that assigns `result = {'rows': [...]}` without a matching `columns` list; note validation checks `rows` first, so this only fires when `rows` is present.
Common situations: Users assuming Redash infers columns from the row dicts (it does not); partial migrations of scripts where the columns line was dropped; copy-paste from examples that omit columns.
Related errors
- Missing `rows` field in `result` dict.
- `rows` field should be of type `list`.
- `columns` field should be of type `list`.
- Query id {} not found.
- Queries of type {} can not be processed by redash.
AI-assisted analysis of getredash/redash@ca79fe988d (2026-08-28).
Data as JSON: /api/errors/f2bfecfc120701a9.
Report an issue: GitHub.