cloudflare/cloudflared · error
aud field is not a string or an array of strings
Error message
aud field is not a string or an array of strings
What it means
jwtPayload.UnmarshalJSON requires the "aud" claim to be either a JSON string or an array of strings. Any other JSON type (number, object, boolean, null) hits the default branch and returns this error, rejecting the token as structurally invalid.
Solutions
- Fix the token issuer to emit aud as a string or an array of strings, e.g. "aud": "app-id" or ["app-id"].
- Decode the token payload (base64 JSON) and confirm the aud claim's JSON type before debugging further.
- If the issuer is fixed but cached tokens persist, discard/regenerate the cached tokens.
Example fix
// before: {"aud": 12345}
// after: {"aud": ["12345"]} Defensive patterns
Strategy: validation
Validate before calling
switch payloadMap["aud"].(type) {
case string, []any:
// acceptable shape (array still needs string-element check)
default:
return fmt.Errorf("aud must be a string or array of strings, got %T", payloadMap["aud"])
} Type guard
func hasValidAudShape(v any) bool {
switch t := v.(type) {
case string:
return t != ""
case []any:
return len(t) > 0
default:
return false
}
} Try / catch
p := jwtPayload{}
if err := json.Unmarshal(rawPayload, &p); err != nil {
if strings.Contains(err.Error(), "aud field") {
return fmt.Errorf("token rejected: aud claim must be string or []string: %w", err)
}
return err
} Prevention
- Standardize token minting so aud is always a string or []string claim.
- Never hand-edit JWT payloads; regenerate tokens through the issuing library.
- Validate the payload JSON shape in tests before shipping a new token producer.
When it happens
Trigger: Unmarshalling a JWT payload whose aud claim is not a string or string-array, e.g. "aud": 12345, "aud": {"tenant":"x"}, or "aud": true.
Common situations: Custom token minters that serialize audience as a numeric client ID or nested object, tokens issued by non-standard services, or manually edited/hand-rolled JWTs used in testing.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- aud array contains non-string elements
- metadata JWT aud is empty
- failed to create app token request
- failed to determine if token is FED
- metadata JWT auth_domain validation failed
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/19246257f2559296.
Report an issue: GitHub.
Appendix: source
Thrown at token/token.go:96
var audParser struct {
Aud any `json:"aud"`
}
if err := json.Unmarshal(data, &audParser); err != nil {
return err
}
switch aud := audParser.Aud.(type) {
case string:
p.Aud = []string{aud}
case []any:
for _, a := range aud {
s, ok := a.(string)
if !ok {
return errors.New("aud array contains non-string elements")
}
p.Aud = append(p.Aud, s)
}
default:
return errors.New("aud field is not a string or an array of strings")
}
return nil
}
func (p jwtPayload) isExpired() bool {
return int(time.Now().Unix()) > p.Exp
}
const (
lockRetryInterval = 2 * time.Second
lockTimeout = 10 * time.Minute
startTimeTolerance = int64(1000) // milliseconds
)
// acquireLockFile loops until it successfully creates a lock file for the
// given token file path. The lock file is created at tokenPath + ".lock".
//
// On each iteration:View on GitHub (pinned to 2253eeeb25)