getredash/redash · error · Exception
{} did not change; possible misconfiguration
Error message
{} did not change; possible misconfiguration What it means
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.
Source
Thrown at redash/query_runner/json_ds.py:277
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], "")
if not next_token:
return False, None, request_options
params = request_options.get("params", {})
# prevent infinite loop that can happen if self.fields[1] is wrong
if next_token == params.get(self.fields[1]):
raise Exception("{} did not change; possible misconfiguration".format(self.fields[0]))
params[self.fields[1]] = next_token
request_options["params"] = params
return True, url, request_options
register(JSON)
View on GitHub (pinned to ca79fe988d)
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
Example fix
// before
{"pagination": {"type": "token"}}
// after
{"pagination": {"type": "token", "fields": ["next_cursor", "cursor"]}} Defensive patterns
Strategy: fallback
Validate before calling
# Inspect one real response first: confirm the token field changes per page
import requests
r1 = requests.get(url); r2 = requests.get(url, params={req_param: token1})
assert r1.json()[resp_field] != r2.json()[resp_field], 'API ignores the token param' Try / catch
try:
run_json_query(query)
except Exception as e:
if 'did not change; possible misconfiguration' in str(e):
# fix pagination.fields[1] / [0], don't retry blindly
log_and_flag_pagination_config() Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Unknown 'pagination.type' {}
- 'pagination.path' should be a string
- 'pagination.fields' should be a list of 2 field names
- Page must be positive integer.
- Page is out of range.
AI-assisted analysis of getredash/redash@ca79fe988d (2026-08-28).
Data as JSON: /api/errors/fc980236b9d26b32.
Report an issue: GitHub.