{"record":{"id":"fc980236b9d26b32","repo":"getredash/redash","slug":"did-not-change-possible-misconfiguration","errorCode":null,"errorMessage":"{} did not change; possible misconfiguration","messagePattern":"(.+?) did not change; possible misconfiguration","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"redash/query_runner/json_ds.py","lineNumber":277,"sourceCode":"        return True, next_url, request_options\n\n\nclass TokenPagination(RequestPagination):\n    def __init__(self, pagination):\n        self.fields = pagination.get(\"fields\", [\"next_page_token\", \"page_token\"])\n        if not isinstance(self.fields, list) or len(self.fields) != 2:\n            raise QueryParseError(\"'pagination.fields' should be a list of 2 field names\")\n\n    def next(self, url, request_options, response):\n        next_token = _apply_path_search(response, self.fields[0], \"\")\n        if not next_token:\n            return False, None, request_options\n\n        params = request_options.get(\"params\", {})\n\n        # prevent infinite loop that can happen if self.fields[1] is wrong\n        if next_token == params.get(self.fields[1]):\n            raise Exception(\"{} did not change; possible misconfiguration\".format(self.fields[0]))\n\n        params[self.fields[1]] = next_token\n        request_options[\"params\"] = params\n        return True, url, request_options\n\n\nregister(JSON)\n","sourceCodeStart":259,"sourceCodeEnd":285,"githubUrl":"https://github.com/getredash/redash/blob/ca79fe988d81cdac9675b412f3dfcab107bc1fbc/redash/query_runner/json_ds.py#L259-L285","documentation":"TokenPagination.next() guards against infinite pagination loops: if the token extracted from the response equals the token already sent in the request params, the endpoint is ignoring your token parameter and the same page would be fetched forever, so it raises this generic Exception. The field named in the message is the response field that didn't change.","triggerScenarios":"pagination.fields[1] (request param name) doesn't match what the API actually accepts (e.g. you send page_token but the API expects cursor), so the API returns the same next-token every page. Also triggered when the response field always returns a constant sentinel token.","commonSituations":"Copied default fields ['next_page_token', 'page_token'] but the API uses different parameter naming; or the API requires the token in a header/path rather than a query param, which this pagination type can't express.","solutions":["Fix pagination.fields[1] to the exact query parameter the API reads for the next-page token","Fix pagination.fields[0] to the exact response field containing the token (a wrong field can yield a constant value)","If the API paginates via URL in the body, switch pagination.type to \"url\"","If the token must go in a header or path, this runner can't express it — fetch via a different approach"],"exampleFix":"// before\n{\"pagination\": {\"type\": \"token\"}}\n// after\n{\"pagination\": {\"type\": \"token\", \"fields\": [\"next_cursor\", \"cursor\"]}}","handlingStrategy":"fallback","validationCode":"# Inspect one real response first: confirm the token field changes per page\nimport requests\nr1 = requests.get(url); r2 = requests.get(url, params={req_param: token1})\nassert r1.json()[resp_field] != r2.json()[resp_field], 'API ignores the token param'","typeGuard":null,"tryCatchPattern":"try:\n    run_json_query(query)\nexcept Exception as e:\n    if 'did not change; possible misconfiguration' in str(e):\n        # fix pagination.fields[1] / [0], don't retry blindly\n        log_and_flag_pagination_config()","preventionTips":["Verify the request param name with the API docs before configuring token pagination","Probe two pages manually to confirm tokens advance","Switch to url pagination when the API supplies next-page links"],"tags":["redash","json-datasource","pagination","infinite-loop-guard"],"backgroundTag":"pagination-loop-detected","analyzedSha":"ca79fe988d81cdac9675b412f3dfcab107bc1fbc","analyzedAt":"2026-08-28T18:32:34.637Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}