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_getattr

View on GitHub (pinned to ca79fe988d)

Solutions

  1. Add `columns` as a list of column metadata dicts, typically `[{'name': ..., 'friendly_name': ..., 'type': ...}]`
  2. Keep `columns` names consistent with the keys used in each row dict
  3. 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

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


AI-assisted analysis of getredash/redash@ca79fe988d (2026-08-28). Data as JSON: /api/errors/f2bfecfc120701a9. Report an issue: GitHub.