cloudflare/cloudflared · error

failed to marshal signPayload

Error message

failed to marshal signPayload

What it means

After extracting JWT claims, SignCert marshals a signPayload struct (public key, JWT, issuer) to JSON to POST to the token issuer's sign endpoint. This error means json.Marshal failed on that struct, which is essentially impossible for plain string fields and usually indicates a programming-level problem (nil dereference via bad input types) rather than user input.

Source

Thrown at sshgen/sshgen.go:110

	parsedToken, err := jwt.ParseSigned(token, signatureAlgs)
	if err != nil {
		return "", errors.Wrap(err, "failed to parse JWT")
	}

	claims := jwt.Claims{}
	err = parsedToken.UnsafeClaimsWithoutVerification(&claims)
	if err != nil {
		return "", errors.Wrap(err, "failed to retrieve JWT claims")
	}

	buf, err := json.Marshal(&signPayload{
		PublicKey: pubKey,
		JWT:       token,
		Issuer:    claims.Issuer,
	})
	if err != nil {
		return "", errors.Wrap(err, "failed to marshal signPayload")
	}
	var res *http.Response
	if mockRequest != nil {
		res, err = mockRequest(claims.Issuer+signEndpoint, "application/json", bytes.NewBuffer(buf))
	} else {
		client := http.Client{
			Timeout: 10 * time.Second,
		}
		res, err = client.Post(claims.Issuer+signEndpoint, "application/json", bytes.NewBuffer(buf))
	}

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

	decoder := json.NewDecoder(res.Body)

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Confirm signPayload fields are JSON-encodable strings or pointers
  2. Log the underlying wrapped error to identify the offending field
  3. If this appears, it is a code bug — fix the signPayload definition rather than retrying
  4. Add a unit test marshaling a representative signPayload

Example fix

// before
buf, err := json.Marshal(&signPayload{PublicKey: pubKey, JWT: token, Issuer: claims.Issuer})
if err != nil {
    return "", errors.Wrap(err, "failed to marshal signPayload")
}
// after
payload := signPayload{PublicKey: pubKey, JWT: token, Issuer: claims.Issuer}
buf, err := json.Marshal(&payload)
if err != nil {
    return "", errors.Wrap(err, fmt.Sprintf("failed to marshal signPayload: unsupported value in %T", payload))
}
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure payload is encodable before the call
if _, err := json.Marshal(signPayload{PublicKey: pubKey, JWT: token, Issuer: issuer}); err != nil {
    return fmt.Errorf("payload not encodable: %w", err)
}

Try / catch

if _, err := SignCert(token, pubKey); err != nil {
    if strings.Contains(err.Error(), "failed to marshal signPayload") {
        return fmt.Errorf("internal encoding bug: %w", err)
    }
}

Prevention

When it happens

Trigger: json.Marshal of the signPayload struct returns an error — practically only when a field holds an unsupported value such as a channel, func, or cyclic value; with current string fields this is effectively dead defensive code.

Common situations: Recompiling sshgen with modified signPayload field types that json cannot encode; extremely rare in normal operation.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


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