getredash/redash · error · QueryParseError

'pagination.path' should be a string

Error message

'pagination.path' should be a string

What it means

UrlPagination validates that the optional 'pagination.path' setting is a string; it defaults to '_links.next.href' (JSON API style). A non-string path (number, object, list) means the config is malformed and the runner cannot locate the next-page URL in responses.

Source

Thrown at redash/query_runner/json_ds.py:251

    @staticmethod
    def from_config(configuration, pagination):
        if not isinstance(pagination, dict) or not isinstance(pagination.get("type"), str):
            raise QueryParseError("'pagination' should be an object with a `type` property")

        if pagination["type"] == "url":
            return UrlPagination(pagination)
        elif pagination["type"] == "token":
            return TokenPagination(pagination)

        raise QueryParseError("Unknown 'pagination.type' {}".format(pagination["type"]))


class UrlPagination(RequestPagination):
    def __init__(self, pagination):
        self.path = pagination.get("path", "_links.next.href")
        if not isinstance(self.path, str):
            raise QueryParseError("'pagination.path' should be a string")

    def next(self, url, request_options, response):
        next_url = _apply_path_search(response, self.path, "")
        if not next_url:
            return False, None, request_options

        next_url = urljoin(url, next_url)
        return True, next_url, request_options


class TokenPagination(RequestPagination):
    def __init__(self, pagination):
        self.fields = pagination.get("fields", ["next_page_token", "page_token"])
        if not isinstance(self.fields, list) or len(self.fields) != 2:
            raise QueryParseError("'pagination.fields' should be a list of 2 field names")

    def next(self, url, request_options, response):
        next_token = _apply_path_search(response, self.fields[0], "")

View on GitHub (pinned to ca79fe988d)

Solutions

  1. Make pagination.path a dotted JSON path string, e.g. "_links.next.href" or "data.next_url"
  2. Omit path to use the default '_links.next.href'
  3. Verify the path actually exists in the API response payload

Example fix

// before
{"pagination": {"type": "url", "path": ["links", "next"]}}
// after
{"pagination": {"type": "url", "path": "links.next"}}
Defensive patterns

Strategy: validation

Validate before calling

path = cfg.get('pagination', {}).get('path', '_links.next.href')
assert isinstance(path, str) and path, 'pagination.path must be a dotted string path'

Type guard

def valid_path(p: dict) -> bool:
    path = p.get('path', '_links.next.href')
    return isinstance(path, str) and len(path) > 0

Prevention

When it happens

Trigger: Supplying {"pagination": {"type": "url", "path": 123}} or "path": ["next"] — any non-string value for pagination.path.

Common situations: Developer passes a JSON pointer array or a dotted path with a typo in type, or a YAML/JSON templating system injects a number/boolean into the field.

Related errors


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