getredash/redash · error · Exception

Missing `rows` field in `result` dict.

Error message

Missing `rows` field in `result` dict.

What it means

Raised by PythonQueryRunner.validate_result (redash/query_runner/python.py:323) when the user-supplied query script builds a `result` dict that has no `rows` key. Redash's Python query runner executes the user's code, then requires the contract that `result` be a non-empty dict containing both `rows` and `columns` lists before the data can be rendered. This error means the script completed but did not assign query results into the expected shape.

Source

Thrown at redash/query_runner/python.py:323

        if user is None:
            raise Exception("Python query helpers require a current user.")
        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

View on GitHub (pinned to ca79fe988d)

Solutions

  1. Add a `rows` key holding a list of dict records to the `result` variable, e.g. `result = {'rows': [...], 'columns': [...]}`
  2. Also include `columns` as a list of column definitions to avoid the next validation failure
  3. If using pandas, convert with `result = {'columns': [{'name': c, 'friendly_name': c} for c in df.columns], 'rows': df.to_dict(orient='records')}`

Example fix

# before
result = {'columns': [{'name': 'id'}]}
# after
result = {'columns': [{'name': 'id'}], 'rows': [{'id': 1}, {'id': 2}]}
Defensive patterns

Strategy: validation

Validate before calling

result = build_result()  # from user script
if 'rows' not in result:
    raise ValueError('script must define result["rows"]')

Type guard

def is_valid_result(r) -> bool:
    return (
        isinstance(r, dict) and bool(r)
        and isinstance(r.get('rows'), list)
        and isinstance(r.get('columns'), list)
    )

Try / catch

try:
    validate_result(result)
except Exception as e:
    raise UserFacingError('Python query output invalid: {}'.format(e))

Prevention

When it happens

Trigger: Running a Python-type query in Redash whose code sets `result = {...}` (or mutates a result dict) without ever putting a `rows` key in it, e.g. `result = {'columns': [...]}` or `result = {'data': ...}`.

Common situations: Users porting pandas/scratch scripts to Redash and returning a DataFrame or arbitrary payload instead of the rows/columns dict; typos like `result['row'] = ...`; forgetting the final `result` assignment entirely (which hits the earlier empty check instead).

Related errors


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