getredash/redash · error · Exception

Invalid JSON response from D1: {str(e)}

Error message

Invalid JSON response from D1: {str(e)}

What it means

D1 runner's _query catches json.JSONDecodeError when the Cloudflare API response body isn't valid JSON and re-raises with the parse detail. The HTTP call succeeded but the body couldn't be parsed.

Source

Thrown at redash/query_runner/d1.py:87

            "Content-Type": "application/json",
        }
        body = {"sql": sql, "params": params or []}

        try:
            resp = session.post(self.configuration.get("cf_url"), headers=headers, data=json.dumps(body), timeout=30)
            resp.raise_for_status()
            data = resp.json()

            # Expected: { "result": [ { "results": [...] } ] }
            results = data.get("result", [])
            if not results:
                return []
            return results[0].get("results", [])

        except session.exceptions.RequestException as e:
            raise Exception(f"Failed to connect to Cloudflare D1: {str(e)}")
        except json.JSONDecodeError as e:
            raise Exception(f"Invalid JSON response from D1: {str(e)}")
        except KeyError as e:
            raise Exception(f"Unexpected response format from D1: {str(e)}")

    def run_query(self, query, user):
        try:
            rows = self._query(query)
            if not rows:
                return {"columns": [], "rows": []}, None

            # Infer columns from first row
            first_row = rows[0]
            columns = []
            for k, v in first_row.items():
                # Get the Python type name and map it to Redash type
                python_type = type(v).__name__
                redash_type = TYPES_MAP.get(python_type, TYPE_STRING)

                # Special handling for strings that look like datetimes

View on GitHub (pinned to ca79fe988d)

Solutions

  1. Reproduce the request with curl and inspect the raw body
  2. Fix proxy/WAF rules that rewrite responses from api.cloudflare.com
  3. Confirm the request URL is the official API endpoint
  4. Retry during a Cloudflare incident if the body is an error page

Example fix

# before
BASE_URL = "https://api.cloudflare.com"

# after
BASE_URL = "https://api.cloudflare.com/client/v4"
Defensive patterns

Strategy: try-catch

Validate before calling

import requests
r = requests.post(url, headers=h, json=body, timeout=10)
r.raise_for_status()
assert r.headers.get('content-type', '').startswith('application/json'), 'proxy is mangling responses'

Try / catch

try:
    rows = d1_runner._query(q)
except Exception as e:
    if 'Invalid JSON response' in str(e):
        inspect_raw_body_with_curl(); flag_proxy_config()

Prevention

When it happens

Trigger: The D1 endpoint returning HTML (a proxy/CDN error page), an empty body, or truncated output that json.loads can't parse.

Common situations: Corporate proxy returning an HTML block page, Cloudflare serving a non-JSON error page during incidents, or a base URL pointing at a non-API host.

Understand the failure class

Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.

Related errors


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