{"record":{"id":"1565a3e982a0dd2d","repo":"getredash/redash","slug":"pagination-should-be-an-object-with-a-type-pro","errorCode":null,"errorMessage":"'pagination' should be an object with a `type` property","messagePattern":"'pagination' should be an object with a `type` property","errorType":"validation","errorClass":"QueryParseError","httpStatus":null,"severity":"warning","filePath":"redash/query_runner/json_ds.py","lineNumber":237,"sourceCode":"    def _get_json_response(self, url, method, **request_options):\n        response, error = self.get_response(url, http_method=method, **request_options)\n        result = response.json() if error is None else {}\n        return result, error\n\n\nclass RequestPagination:\n    def next(self, url, request_options, response):\n        \"\"\"Checks the response for another page.\n\n        Returns:\n            has_more, next_url, next_request_options\n        \"\"\"\n        return False, None, request_options\n\n    @staticmethod\n    def from_config(configuration, pagination):\n        if not isinstance(pagination, dict) or not isinstance(pagination.get(\"type\"), str):\n            raise QueryParseError(\"'pagination' should be an object with a `type` property\")\n\n        if pagination[\"type\"] == \"url\":\n            return UrlPagination(pagination)\n        elif pagination[\"type\"] == \"token\":\n            return TokenPagination(pagination)\n\n        raise QueryParseError(\"Unknown 'pagination.type' {}\".format(pagination[\"type\"]))\n\n\nclass UrlPagination(RequestPagination):\n    def __init__(self, pagination):\n        self.path = pagination.get(\"path\", \"_links.next.href\")\n        if not isinstance(self.path, str):\n            raise QueryParseError(\"'pagination.path' should be a string\")\n\n    def next(self, url, request_options, response):\n        next_url = _apply_path_search(response, self.path, \"\")\n        if not next_url:","sourceCodeStart":219,"sourceCodeEnd":255,"githubUrl":"https://github.com/getredash/redash/blob/ca79fe988d81cdac9675b412f3dfcab107bc1fbc/redash/query_runner/json_ds.py#L219-L255","documentation":"Pagination for JSON URL queries is configured via a 'pagination' object whose required 'type' selects the strategy ('url' or 'token'). Pagination.from_config validates it is a dict with a string type; otherwise it raises QueryParseError with this message.","triggerScenarios":"Setting pagination: url (a string), pagination: [ ... ] (list), omitting 'type', or misspelling 'type' (e.g. 'kind') in the query YAML.","commonSituations":"Adapting pagination examples and dropping the type key, wrong indentation making pagination a scalar, or using an unsupported type value.","solutions":["Use pagination: {type: url, ...} or pagination: {type: token, ...} with correct nesting","Ensure 'type' is present and one of the two supported strings; fix indentation so pagination is a mapping"],"exampleFix":"# before\npagination:\n  next_page: next\n# after\npagination:\n  type: token\n  next_page: next","handlingStrategy":"type-guard","validationCode":"def pagination_ok(q: dict) -> bool:\n    p = q.get(\"pagination\")\n    return p is None or (isinstance(p, dict) and isinstance(p.get(\"type\"), str))","typeGuard":"import yaml\n\ndef is_valid_json_ds_query(q: str) -> bool:\n    try:\n        parsed = yaml.safe_load(q)\n    except yaml.YAMLError:\n        return False\n    if not isinstance(parsed, dict) or \"url\" not in parsed:\n        return False\n    p = parsed.get(\"pagination\")\n    return p is None or (isinstance(p, dict) and p.get(\"type\") in (\"url\", \"token\"))","tryCatchPattern":null,"preventionTips":["Write pagination as a mapping with type: url or type: token","Double-check indentation of nested pagination keys","Copy pagination blocks from working examples"],"tags":["json-ds","pagination","yaml","type-validation"],"backgroundTag":"invalid-query-format","analyzedSha":"ca79fe988d81cdac9675b412f3dfcab107bc1fbc","analyzedAt":"2026-08-28T18:32:34.637Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}