wtfutil/wtf · error

invalid response returned from Pi-hole Server %s

Error message

 invalid response returned from Pi-hole Server
 %s

What it means

After reading the body, checkServer unmarshals it into a struct expecting {"version": <int>}. If the body is not valid JSON in that shape, the library reports an invalid response from the Pi-hole server.

Source

Thrown at modules/pihole/client.go:340

	}()

	if resp.StatusCode >= http.StatusBadRequest {
		return fmt.Errorf(" failed to retrieve version from Pi-hole server\n http status code: %d",
			resp.StatusCode)
	}

	var vResp struct {
		Version int `json:"version"`
	}

	var rBody []byte

	if rBody, err = io.ReadAll(resp.Body); err != nil {
		return fmt.Errorf(" Pi-hole server failed to respond\n %s", parseError(err))
	}

	if err = json.Unmarshal(rBody, &vResp); err != nil {
		return fmt.Errorf(" invalid response returned from Pi-hole Server\n %s", parseError(err))
	}

	if vResp.Version != 3 {
		return fmt.Errorf(" only Pi-hole API version 3 is supported\n version %d was detected", vResp.Version)
	}

	return err
}

func (widget *Widget) adblockSwitch(action string) {
	var req *http.Request

	var url *url2.URL
	url, _ = url2.Parse(widget.settings.apiUrl)

	var query url2.Values
	query, _ = url2.ParseQuery(url.RawQuery)

View on GitHub (pinned to bb838c1ccb)

Solutions

  1. Point apiUrl at admin/api.php of a Pi-hole whose API returns the classic {"version":3} payload
  2. Curl '<apiUrl>?version' and verify the body is JSON with a numeric version field
  3. If running Pi-hole v6, downgrade expectations or use a widget version supporting the new API

Example fix

// before: HTML login page returned
// after: ensure auth token configured so JSON is returned
apiUrl: http://pi.hole/admin/api.php
authToken: <correct-token>
Defensive patterns

Strategy: validation

Validate before calling

resp, err := http.Get(apiURL + "?version")
if err == nil {
    body, _ := io.ReadAll(io.LimitReader(resp.Body, 256))
    if !json.Valid(body) {
        log.Printf("endpoint returned non-JSON (likely HTML/auth page): %.80s", body)
    }
}

Try / catch

if err := widget.checkServer(*client, apiUrl); err != nil {
    if strings.Contains(err.Error(), "invalid response returned") {
        log.Printf("unexpected payload from Pi-hole, verify version/schema: %v", err)
    }
}

Prevention

When it happens

Trigger: json.Unmarshal(rBody, &vResp) fails in checkServer — the version endpoint returned non-JSON or JSON not matching {version:int}.

Common situations: apiUrl points at an HTML dashboard or login page, a Pi-hole v6 (new API) returns a different JSON envelope, or the response is a string like 'error' from a proxy.

Related errors


AI-assisted analysis of wtfutil/wtf@bb838c1ccb (2026-09-03). Data as JSON: /api/errors/8ea3c2a938060c92. Report an issue: GitHub.