{"record":{"id":"97b22ae5fe401eb6","repo":"getredash/redash","slug":"unexpected-response-format-from-d1-str-e","errorCode":null,"errorMessage":"Unexpected response format from D1: {str(e)}","messagePattern":"Unexpected response format from D1: (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"redash/query_runner/d1.py","lineNumber":89,"sourceCode":"        body = {\"sql\": sql, \"params\": params or []}\n\n        try:\n            resp = session.post(self.configuration.get(\"cf_url\"), headers=headers, data=json.dumps(body), timeout=30)\n            resp.raise_for_status()\n            data = resp.json()\n\n            # Expected: { \"result\": [ { \"results\": [...] } ] }\n            results = data.get(\"result\", [])\n            if not results:\n                return []\n            return results[0].get(\"results\", [])\n\n        except session.exceptions.RequestException as e:\n            raise Exception(f\"Failed to connect to Cloudflare D1: {str(e)}\")\n        except json.JSONDecodeError as e:\n            raise Exception(f\"Invalid JSON response from D1: {str(e)}\")\n        except KeyError as e:\n            raise Exception(f\"Unexpected response format from D1: {str(e)}\")\n\n    def run_query(self, query, user):\n        try:\n            rows = self._query(query)\n            if not rows:\n                return {\"columns\": [], \"rows\": []}, None\n\n            # Infer columns from first row\n            first_row = rows[0]\n            columns = []\n            for k, v in first_row.items():\n                # Get the Python type name and map it to Redash type\n                python_type = type(v).__name__\n                redash_type = TYPES_MAP.get(python_type, TYPE_STRING)\n\n                # Special handling for strings that look like datetimes\n                if python_type == \"str\" and detect_datetime_string(v):\n                    redash_type = TYPE_DATETIME","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/getredash/redash/blob/ca79fe988d81cdac9675b412f3dfcab107bc1fbc/redash/query_runner/d1.py#L71-L107","documentation":"D1 runner's _query catches KeyError while drilling into the response envelope — typically 'result' missing from the JSON or results[0] lacking 'results' — and re-raises as 'Unexpected response format from D1'. The API replied with JSON but not the expected success shape.","triggerScenarios":"Cloudflare returns a JSON error envelope like {\"success\": false, \"errors\": [...]} with no 'result' key (bad API token, nonexistent database, malformed SQL), so the results[0] lookup chain KeyErrors.","commonSituations":"Revoked or insufficient API token, deleted or wrong database_id, or an API version change altering the envelope shape.","solutions":["Check the embedded key name and inspect the raw response with curl using the same token","Verify the API token has D1 permissions and the database_id exists","Validate SQL syntax — malformed statements can return error envelopes","Update Redash if Cloudflare changed the D1 response schema"],"exampleFix":"# before\nresults = data.get(\"result\", [])\nreturn results[0].get(\"results\", [])\n\n# after\nif not data.get(\"success\"):\n    raise Exception(f\"D1 API error: {data.get('errors')}\")\nresults = data.get(\"result\", [])\nreturn results[0].get(\"results\", []) if results else []","handlingStrategy":"validation","validationCode":"import requests\nr = requests.post(url, headers=h, json=body, timeout=10)\ndata = r.json()\nassert data.get('success'), data.get('errors')  # check envelope before relying on 'result'","typeGuard":"def is_d1_success_envelope(data: dict) -> bool:\n    return isinstance(data, dict) and data.get('success') is True and 'result' in data","tryCatchPattern":"try:\n    rows = d1_runner._query(q)\nexcept Exception as e:\n    if 'Unexpected response format' in str(e):\n        errors = fetch_raw_api_errors(); route_token_or_sql_fix(errors)","preventionTips":["Check the success flag on every Cloudflare API response in custom code","Rotate D1 tokens before expiry with calendar alerts","Re-verify database_id after workspace reorganizations"],"tags":["redash","cloudflare-d1","api-response","keyerror"],"backgroundTag":"unexpected-api-response","analyzedSha":"ca79fe988d81cdac9675b412f3dfcab107bc1fbc","analyzedAt":"2026-08-28T18:32:34.637Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}