{"record":{"id":"754dded0bf248bf7","repo":"wtfutil/wtf","slug":"failed-to-parse-query-types-response-s","errorCode":null,"errorMessage":" failed to parse query types response\n %s","messagePattern":" failed to parse query types response\n (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/pihole/client.go","lineNumber":288,"sourceCode":"\tdefer func() {\n\t\tif closeErr := resp.Body.Close(); closeErr != nil {\n\t\t\treturn\n\t\t}\n\t}()\n\n\tif resp.StatusCode >= http.StatusBadRequest {\n\t\treturn qt, fmt.Errorf(\" failed to retrieve version from Pi-hole server\\n http status code: %d\",\n\t\t\tresp.StatusCode)\n\t}\n\n\tvar rBody []byte\n\n\tif rBody, err = io.ReadAll(resp.Body); err != nil {\n\t\treturn qt, fmt.Errorf(\" failed to read top clients response\\n %s\", parseError(err))\n\t}\n\n\tif err = json.Unmarshal(rBody, &qt); err != nil {\n\t\treturn qt, fmt.Errorf(\" failed to parse query types response\\n %s\", parseError(err))\n\t}\n\n\treturn qt, err\n}\n\nfunc checkServer(c http.Client, apiURL string) error {\n\tvar err error\n\n\tvar req *http.Request\n\n\tvar url *url2.URL\n\n\tif url, err = url2.Parse(apiURL); err != nil {\n\t\treturn fmt.Errorf(\" failed to parse API URL\\n %s\", parseError(err))\n\t}\n\n\tif url.Host == \"\" {\n\t\treturn fmt.Errorf(\" please specify 'apiUrl' in Pi-hole settings, e.g.\\n apiUrl: http://<server>:<port>/admin/api.php\")","sourceCodeStart":270,"sourceCodeEnd":306,"githubUrl":"https://github.com/wtfutil/wtf/blob/bb838c1ccb0f0f3223690df44afdec663d622881/modules/pihole/client.go#L270-L306","documentation":"This error comes from the Pi-hole widget's getQueryTypes function when the HTTP response body from the Pi-hole API cannot be unmarshaled into the query-types data structure. The library fetched the top/query-types endpoint successfully but the JSON payload did not match the expected shape. parseError wraps the underlying json.Unmarshal error with source context.","triggerScenarios":"io.ReadAll succeeded but json.Unmarshal(rBody, &qt) failed while parsing the query types endpoint response in getQueryTypes (called from getTopClientsView).","commonSituations":"Pi-hole returns an HTML login page instead of JSON (missing/expired auth token), the apiUrl points at Pi-hole v5/v6 whose response schema differs, a proxy or captive portal returns an error page, or the response is empty/truncated.","solutions":["Verify the Pi-hole API version is 3-compatible and the apiUrl points to the correct api.php endpoint","Confirm auth settings (API token/webpassword) are correct so Pi-hole returns JSON, not an auth/HTML page","Curl the query types endpoint manually (apiUrl?getQueryTypes) and inspect the raw response for HTML or schema drift","Update the widget/library if your Pi-hole version changed its JSON schema"],"exampleFix":"// before: apiUrl pointing at a dashboard URL returning HTML\napiUrl: http://pi.hole/admin/\n// after: apiUrl pointing at the api.php endpoint\napiUrl: http://pi.hole/admin/api.php","handlingStrategy":"validation","validationCode":"resp, err := http.Get(apiURL + \"?getQueryTypes\")\nif err == nil {\n    var probe struct{ QueryTypes map[string]int `json:\"query_types\"` }\n    if jsonErr := json.NewDecoder(resp.Body).Decode(&probe); jsonErr != nil {\n        // config/auth problem: response is not expected JSON\n    }\n}","typeGuard":null,"tryCatchPattern":"qt, err := widget.getQueryTypes()\nif err != nil {\n    log.Printf(\"query types unavailable, skipping panel: %v\", err)\n    return\n}","preventionTips":["Verify apiUrl returns JSON (not HTML) with curl before configuring","Keep Pi-hole API version compatible with the widget","Set a valid API token so auth pages are never returned"],"tags":["json","pi-hole","parsing","http-response"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"bb838c1ccb0f0f3223690df44afdec663d622881","analyzedAt":"2026-09-03T17:02:45.030Z","contentChangedAt":"2026-09-03T17:02:45.030Z","schemaVersion":2},"datasetVersion":"2026-09-11T00:17:11.886Z"}