{"record":{"id":"c4fef8b4ed825abc","repo":"wtfutil/wtf","slug":"failed-to-retrieve-status-check-provided-api-url","errorCode":null,"errorMessage":" failed to retrieve status: check provided api URL and token\n %s","messagePattern":" failed to retrieve status: check provided api URL and token\n (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/pihole/client.go","lineNumber":79,"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 status, 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 status, fmt.Errorf(\" failed to read status response\")\n\t}\n\n\tif err = json.Unmarshal(rBody, &status); err != nil {\n\t\treturn status, fmt.Errorf(\" failed to retrieve status: check provided api URL and token\\n %s\",\n\t\t\tparseError(err))\n\t}\n\n\treturn status, err\n}\n\ntype FlexInt int\n\nfunc (fi *FlexInt) UnmarshalJSON(b []byte) error {\n\tif b[0] != '\"' {\n\t\treturn json.Unmarshal(b, (*int)(fi))\n\t}\n\n\tvar s string\n\n\tif err := json.Unmarshal(b, &s); err != nil {\n\t\treturn err\n\t}","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/wtfutil/wtf/blob/bb838c1ccb0f0f3223690df44afdec663d622881/modules/pihole/client.go#L61-L97","documentation":"getStatus in modules/pihole/client.go wraps a json.Unmarshal failure while decoding the Pi-hole /api (status) HTTP response body into the status struct. The library throws it because the response bytes could not be decoded as the expected JSON shape. It is not a network problem — the HTTP call succeeded but the payload was not valid JSON of the expected shape.","triggerScenarios":"The Pi-hole HTTP endpoint returned a 200 response whose body is not JSON matching the expected status struct — e.g. an HTML login/error page, an empty body, or JSON with a different schema than `json.Unmarshal(rBody, &status)` expects in getStatus.","commonSituations":"Wrong apiUrl pointing at the Pi-hole web root instead of the API path; missing/invalid webpassword token so Pi-hole returns an HTML session page; pointing the client at a reverse proxy or another service; Pi-hole v6 API response schema differing from what this client expects; a proxy or captive portal intercepting the request.","solutions":["Verify settings.apiUrl points to the correct Pi-hole API endpoint (e.g. http://pi.hole/admin/api.php) and that curl on that URL returns JSON.","Check that settings.token matches the webPassword from /etc/pihole/setupVars.conf (or the v6 app password) — an invalid token commonly yields HTML/JSON-auth-error bodies.","Curl the URL with the auth token and inspect the raw body to confirm the JSON schema matches what getStatus unmarshals into.","Confirm you are not being redirected by a reverse proxy to a login page; adjust proxy/API URL accordingly."],"exampleFix":"// before\nsettings := &Settings{apiUrl: \"http://pi.hole/admin/\", token: \"\"}\n// after\nsettings := &Settings{apiUrl: \"http://pi.hole/admin/api.php\", token: webPasswordFromSetupVars}","handlingStrategy":"try-catch","validationCode":"// Go: verify the endpoint returns parseable JSON before use\nresp, err := http.Get(settings.apiUrl + \"?auth=\" + settings.token)\nif err == nil {\n    var probe map[string]json.RawMessage\n    body, _ := io.ReadAll(resp.Body)\n    if json.Unmarshal(body, &probe) != nil {\n        return errors.New(\"Pi-hole endpoint did not return valid JSON; check apiUrl and token\")\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := client.GetSummaryView(ctx); err != nil {\n    if strings.Contains(err.Error(), \"failed to retrieve status\") {\n        // log raw response body, verify token/apiUrl, back off and reconfigure\n        log.Printf(\"Pi-hole status decode failed: %v\", err)\n        return\n    }\n    return err\n}","preventionTips":["Curl the apiUrl with the token once at startup and assert the body is JSON.","Keep the token in sync with the Pi-hole webPassword after Pi-hole upgrades.","Pin the client version to your Pi-hole major version (legacy 5.x vs v6 API).","Point apiUrl at the JSON API endpoint, not the web UI root."],"tags":["json","unmarshal","pihole","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"}