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.

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)

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.