bytebase/bytebase · error

subject mismatch: expected pattern %q, got %q

Error message

subject mismatch: expected pattern %q, got %q

What it means

ValidateToken in the WIF (workload identity federation) plugin rejects a token whose `sub` claim does not match the configured SubjectPattern regex. The pattern is an admin-defined allow-list for which federated identities may exchange tokens; a mismatch means the token's subject is outside that allow-list. The error message includes both the expected pattern and the actual subject for debugging.

Source

Thrown at backend/plugin/idp/wif/wif.go:69

		claims.Expiry = registeredClaims.Expiry.Time().Unix()
	}
	if registeredClaims.IssuedAt != nil {
		claims.IssuedAt = registeredClaims.IssuedAt.Time().Unix()
	}

	// Validate issuer
	if claims.Issuer != config.IssuerUrl {
		return nil, errors.Errorf("issuer mismatch: expected %q, got %q", config.IssuerUrl, claims.Issuer)
	}

	// Validate audience (skip if no allowed audiences configured)
	if len(config.AllowedAudiences) > 0 && !validateAudience(claims.Audience, config.AllowedAudiences) {
		return nil, errors.Errorf("audience mismatch: token has %v, allowed %v", claims.Audience, config.AllowedAudiences)
	}

	// Validate subject pattern
	if !matchSubjectPattern(claims.Subject, config.SubjectPattern) {
		return nil, errors.Errorf("subject mismatch: expected pattern %q, got %q", config.SubjectPattern, claims.Subject)
	}

	// Validate expiry
	if time.Now().Unix() > claims.Expiry {
		return nil, errors.New("token has expired")
	}

	return claims, nil
}

func validateAudience(tokenAudience []string, allowedAudiences []string) bool {
	for _, allowed := range allowedAudiences {
		for _, aud := range tokenAudience {
			if aud == allowed {
				return true
			}
		}
	}

View on GitHub (pinned to 1870550677)

Solutions

  1. Print/inspect the token's `sub` claim (decode the JWT payload) and compare against config.SubjectPattern.
  2. Update the WIF config SubjectPattern to match the legitimate subject format, or re-issue/obtain the token from the expected identity.
  3. Test the regex (e.g. Go regexp.MatchString) against the actual subject outside the service to confirm the pattern is correct.
  4. If the subject should never be restricted, clear/omit SubjectPattern so the check is skipped (matchSubjectPattern passes when pattern is empty).

Example fix

// before: pattern assumes GitHub Actions but token is from AWS
config.SubjectPattern = `^repo:myorg/myapp:.*`
// after: match the AWS ARN subject actually present in the token
config.SubjectPattern = `^arn:aws:sts::123456789012:assumed-role/.+`
Defensive patterns

Strategy: validation

Validate before calling

import "regexp"
func subjectMatches(pattern, subject string) bool {
    if pattern == "" { return true }
    re, err := regexp.Compile(pattern)
    return err == nil && re.MatchString(subject)
}
// call before ExchangeToken:
if !subjectMatches(cfg.SubjectPattern, claims.Subject) { /* surface error or fix pattern */ }

Type guard

func hasValidSubject(tok *wif.Token, pattern string) bool {
    return tok != nil && tok.Claims != nil && subjectMatches(pattern, tok.Claims.Subject)
}

Prevention

When it happens

Trigger: ExchangeToken -> ValidateToken is called with a WIF token whose claims.Subject fails matchSubjectPattern against config.SubjectPattern (non-nil pattern that does not regex-match the sub claim).

Common situations: Admin tightens the subject pattern after tokens were already issued; token comes from a different service account/identity than the pattern expects (e.g. pattern `^repo:org/app:.*` but token subject is `repo:org/other:ref`); pattern uses wrong regex syntax or wrong platform prefix (AWS ARN vs GCP service-account email); trailing/leading whitespace or casing differences in the sub claim.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of bytebase/bytebase@1870550677 (2026-09-06). Data as JSON: /api/errors/7df7da41867f4741. Report an issue: GitHub.