getredash/redash · warning · QueryParseError
'fields' needs to be a list.
Error message
'fields' needs to be a list.
What it means
Optional 'fields' in a JSON URL query selects/renames output columns; _run_json_query validates it is a list, and any truthy non-list (string, dict, number) raises QueryParseError("'fields' needs to be a list.").
Source
Thrown at redash/query_runner/json_ds.py:195
fields = query.get("fields")
path = query.get("path")
if "pagination" in query:
pagination = RequestPagination.from_config(self.configuration, query["pagination"])
else:
pagination = None
if isinstance(request_options.get("auth", None), list):
request_options["auth"] = tuple(request_options["auth"])
elif self.configuration.get("username") or self.configuration.get("password"):
request_options["auth"] = (self.configuration.get("username"), self.configuration.get("password"))
if method not in ("get", "post"):
raise QueryParseError("Only GET or POST methods are allowed.")
if fields and not isinstance(fields, list):
raise QueryParseError("'fields' needs to be a list.")
results, error = self._get_all_results(query["url"], method, path, pagination, **request_options)
return parse_json(results, fields), error
def _get_all_results(self, url, method, result_path, pagination, **request_options):
"""Get all results from a paginated endpoint."""
base_url = self.configuration.get("base_url")
url = urljoin(base_url, url)
results = []
has_more = True
while has_more:
response, error = self._get_json_response(url, method, **request_options)
has_more = False
result = _normalize_json(response, result_path)
if result:
results.extend(result)View on GitHub (pinned to ca79fe988d)
Solutions
- Wrap values in a list: fields: [id, name] or block-style '-' items
- For renaming, use list-of-mappings pairs like fields: [{name: newName}] as documented by the runner
Example fix
# before fields: name # after fields: [name]
Defensive patterns
Strategy: type-guard
Validate before calling
def fields_ok(q: dict) -> bool:
f = q.get("fields")
return f is None or isinstance(f, list) Type guard
import yaml
def is_valid_json_ds_query(q: str) -> bool:
try:
parsed = yaml.safe_load(q)
except yaml.YAMLError:
return False
if not isinstance(parsed, dict) or "url" not in parsed:
return False
f = parsed.get("fields")
if f is not None and not isinstance(f, list):
return False
return True Prevention
- Always write fields as a YAML list ([a, b] or '-' items)
- Single field still needs brackets: fields: [name]
- Lint parsed query types before execution
When it happens
Trigger: Writing fields: name (a YAML string) or fields: {name: name} instead of a sequence; note that a single-element flow-style value must still be a list (fields: [name]).
Common situations: Users writing a single field without brackets, or mapping old/new names as a dict instead of pairs inside a list.
Related errors
- 'pagination' should be an object with a `type` property
- Query is empty.
- Query should be a YAML object describing the URL to query.
- Query must include 'url' option.
- Couldn't find path {} in response.
AI-assisted analysis of getredash/redash@ca79fe988d (2026-08-28).
Data as JSON: /api/errors/917045aa799cd25a.
Report an issue: GitHub.