cloudflare/cloudflared · error

failed to decode HTTP response

Error message

failed to decode HTTP response

What it means

After a successful (status 200) response, SignCert decodes the response body into a signResponse struct. This error means the 200 body was not valid JSON or did not match the expected shape, so the signed certificate could not be extracted.

Solutions

  1. Log/dump the raw response body to see what was actually returned
  2. Confirm no proxy or captive portal is intercepting requests to the issuer domain
  3. Update cloudflared — the sign endpoint response format may have changed
  4. Retry the request; transient truncation can cause decode failures

Example fix

// before
var signRes signResponse
if err := decoder.Decode(&signRes); err != nil {
    return "", errors.Wrap(err, "failed to decode HTTP response")
}
// after
var signRes signResponse
if err := decoder.Decode(&signRes); err != nil {
    body, _ := io.ReadAll(res.Body)
    return "", errors.Wrap(err, fmt.Sprintf("failed to decode HTTP response: %q", string(body)))
}
Defensive patterns

Strategy: retry

Try / catch

cert, err := SignCert(token, pubKey)
if err != nil && strings.Contains(err.Error(), "failed to decode HTTP response") {
    // log raw body via a custom mockRequest to inspect actual response, then retry
    log.Warn().Err(err).Msg("unexpected sign response; retrying")
    cert, err = SignCert(token, pubKey)
}

Prevention

When it happens

Trigger: The cert_sign endpoint returns 200 with an empty, HTML, or otherwise malformed body; a proxy intercepts and rewrites the response.

Common situations: Captive portals or proxies returning HTML with status 200; Cloudflare API changes altering the response schema; truncated responses on flaky connections.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06). Data as JSON: /api/errors/045ff90cd9a0e09e. Report an issue: GitHub.

Appendix: source

Thrown at sshgen/sshgen.go:139

	if err != nil {
		return "", errors.Wrap(err, "failed to send request")
	}
	defer res.Body.Close()

	decoder := json.NewDecoder(res.Body)

	if res.StatusCode != 200 {
		var errResponse errorResponse
		if err := decoder.Decode(&errResponse); err != nil {
			return "", err
		}
		return "", fmt.Errorf("%d: %s", errResponse.Status, errResponse.Message)
	}

	var signRes signResponse
	if err := decoder.Decode(&signRes); err != nil {
		return "", errors.Wrap(err, "failed to decode HTTP response")
	}
	return signRes.Certificate, nil
}

// generateKeyPair creates a EC keypair (P256) and stores them in the homedir.
// returns the generated public key from the successful keypair generation
func generateKeyPair(fullName string) ([]byte, error) {
	pubKeyName := fullName + ".pub"

	exist, err := config.FileExists(pubKeyName)
	if err != nil {
		return nil, err
	}
	if exist {
		return os.ReadFile(pubKeyName)
	}

	key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)

View on GitHub (pinned to 2253eeeb25)