We pass `null` for the class name here:

https://github.com/elastic/elasticsearch/blob/f086dd18ddc705bf84a1ff99d35196ec2498fd52/server/src/main/java/org/elasticsearch/plugins/PluginDescriptor.java#L261

However the class name is mandatory for the transport protocol today:

https://github.com/elastic/elasticsearch/blob/f086dd18ddc705bf84a1ff99d35196ec2498fd52/server/src/main/java/org/elasticsearch/plugins/PluginDescriptor.java#L156

This prevents various APIs from working in a cluster with stable plugins installed.
server/src/test/java/org/elasticsearch/plugins/PluginsServiceTests.java
providers = service.loadServiceProviders(TestService.class);
            assertEquals(1, providers.size());
            assertThat(providers.stream().map(p -> p.name()).toList(), containsInAnyOrder("integer"));
            service = newMockPluginsService(new ArrayList<>());
            providers = service.loadServiceProviders(TestService.class);
            assertEquals(0, providers.size());
        } finally {
            PrivilegedOperations.closeURLClassLoader(fakeClassLoader);
            PrivilegedOperations.closeURLClassLoader(fakeClassLoader1);
        }
    }
    
    
    public void testLoadServiceProvidersInSameClassLoader() {
        PluginsService service = newMockPluginsService(List.of(BarPlugin.class, PluginOther.class));
        
        
        @SuppressWarnings("unchecked")
        List<TestService> testServices = (List<TestService>) service.loadServiceProviders(TestService.class);
        assertEquals(1, testServices.size());
        var fooPlugin = (BarPlugin) service.plugins().stream().filter(p -> p.instance() instanceof BarPlugin).findAny().get().instance();
        var othPlugin = (PluginOther) service.plugins()
            .stream()
            .filter(p -> p.instance() instanceof PluginOther)
            .findAny()
            .get()
            .instance();
        
        assertThat(MockPluginsService.createExtensions(TestService.class, othPlugin, e -> false), empty());