getredash/redash · error · Exception

local variable `result` should not be empty.

Error message

local variable `result` should not be empty.

What it means

validate_result() enforces that the Python query's `result` variable is a non-empty dict containing 'rows' and 'columns'. This first check fires when result is None, an empty dict, 0, empty list, etc. — i.e. the user's script finished without producing a result payload.

Source

Thrown at redash/query_runner/python.py:319

        return self._get_current_user().to_dict()

    def _get_current_user(self):
        user = getattr(self, "_current_user", None)
        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")

View on GitHub (pinned to ca79fe988d)

Solutions

  1. Always initialize and populate `result = {'columns': [], 'rows': []}` at the end of the script, even with zero rows
  2. Ensure the code path that sets result is unconditional (move initialization to the top)
  3. When there's no data, still add columns via add_result_column and leave rows empty

Example fix

# before
if data:
    result = {'columns': cols, 'rows': data}
# after
result = {'columns': [], 'rows': []}
if data:
    result['rows'] = data
for c in cols:
    add_result_column(result, c, c, 'string')
Defensive patterns

Strategy: validation

Validate before calling

result = {'columns': [], 'rows': []}  # initialize first
# ... populate unconditionally before script ends
assert isinstance(result, dict) and result

Type guard

def result_ok(r) -> bool:
    return isinstance(r, dict) and bool(r) and 'rows' in r and 'columns' in r

Prevention

When it happens

Trigger: A Python query that never assigns `result = {...}`, assigns it conditionally and a branch skipped it, or leaves it as an empty dict because no rows matched before add_result_column calls.

Common situations: Authors prototype scripts that print instead of building result; loops that populate result only when data exists and today's data is empty; early return/exception handling leaving result unset.

Related errors


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