vxcontrol/pentagi · error

token is invalid

Error message

token is invalid

What it means

After parsing succeeds with no error, ValidateAPIToken double-checks token.Valid; if false it returns "token is invalid". With jwt/v5 this is a defensive branch — if ParseWithClaims returned no error, token.Valid is normally true — but it guards against any parser state where claims parsed yet validity was not established.

Source

Thrown at backend/pkg/server/auth/api_token_jwt.go:58

	token, err := jwt.ParseWithClaims(tokenString, &claims, func(token *jwt.Token) (any, error) {
		// verify signing algorithm to prevent "alg: none"
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return MakeJWTSigningKey(globalSalt), nil
	})
	if err != nil {
		if errors.Is(err, jwt.ErrTokenMalformed) {
			return nil, fmt.Errorf("token is malformed")
		} else if errors.Is(err, jwt.ErrTokenExpired) || errors.Is(err, jwt.ErrTokenNotValidYet) {
			return nil, fmt.Errorf("token is either expired or not active yet")
		} else {
			return nil, fmt.Errorf("token invalid: %w", err)
		}
	}

	if !token.Valid {
		return nil, fmt.Errorf("token is invalid")
	}

	return &claims, nil
}

View on GitHub (pinned to ea665308ba)

Solutions

  1. Treat as a hard authentication failure: reject the request and return 401
  2. Log token subject/tokenID (never the raw token) to identify which credential failed
  3. Pin/verify the golang-jwt/jwt/v5 version for consistent Valid semantics
  4. Report upstream if reproducible, including how the token was constructed
Defensive patterns

Strategy: type-guard

Type guard

func isHardInvalid(err error) bool {
    return err != nil && strings.Contains(err.Error(), "token is invalid")
}

Try / catch

claims, err := auth.ValidateAPIToken(tok, salt)
if err != nil {
    if strings.Contains(err.Error(), "token is invalid") {
        log.Error("parser returned non-valid token without error; failing closed")
    }
    return err // always fail closed
}

Prevention

When it happens

Trigger: Practically only reached if a future/patched jwt/v5 behavior returns err==nil with token.Valid==false, or custom claims' validation hooks invalidate the token without returning an error that maps to the other branches.

Common situations: Upgrading golang-jwt/jwt versions introduces new validity semantics; test mocks returning a non-valid token with nil error.

Understand the failure class

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/d29d3523dd478467. Report an issue: GitHub.