apache/pulsar · error · IllegalArgumentException

Function runtime customizer %s must implement KubernetesMani

Error message

Function runtime customizer %s must implement KubernetesManifestCustomizer

What it means

KubernetesRuntimeFactory.initialize validates that the configured function runtime customizer class implements KubernetesManifestCustomizer before using it. If a class was configured via functionsWorkerCustomNarWindowTitle/customizer property but does not implement the required interface, initialization fails fast with IllegalArgumentException.

Source

Thrown at pulsar-functions/runtime/src/main/java/org/apache/pulsar/functions/runtime/kubernetes/KubernetesRuntimeFactory.java:232

        this.functionInstanceMinResources = workerConfig.getFunctionInstanceMinResources();
        this.functionInstanceMaxResources = workerConfig.getFunctionInstanceMaxResources();
        this.functionInstanceResourceGranularities = workerConfig.getFunctionInstanceResourceGranularities();
        this.functionInstanceResourceChangeInLockStep = workerConfig.isFunctionInstanceResourceChangeInLockStep();
        this.secretsProviderConfigurator = secretsProviderConfigurator;
        this.authenticationEnabled = workerConfig.isAuthenticationEnabled();
        this.javaInstanceJarFile = this.pulsarRootDir + "/instances/java-instance.jar";
        this.pythonInstanceFile = this.pulsarRootDir + "/instances/python-instance/python_instance_main.py";
        this.serverCaBytes = workerConfig.getTlsTrustChainBytes();
        try {
            setupClient();
        } catch (Exception e) {
            log.error().exception(e).log("Failed to setup client");
            throw new RuntimeException(e);
        }
        // make sure the provided class is a kubernetes auth provider, this needs to run before the authProvider!
        if (runtimeCustomizer.isPresent()) {
            if (!(runtimeCustomizer.get() instanceof KubernetesManifestCustomizer)) {
                throw new IllegalArgumentException("Function runtime customizer "
                        + runtimeCustomizer.get().getClass().getName()
                        + " must implement KubernetesManifestCustomizer");
            } else {
                KubernetesManifestCustomizer manifestCustomizer =
                        (KubernetesManifestCustomizer) runtimeCustomizer.get();
                this.manifestCustomizer = Optional.of(manifestCustomizer);
            }
        } else {
            this.manifestCustomizer = Optional.empty();
        }

        // make sure the provided class is a kubernetes auth provider
        if (functionAuthProvider.isPresent()) {
            if (!(functionAuthProvider.get() instanceof KubernetesFunctionAuthProvider)) {
                throw new IllegalArgumentException("Function authentication provider "
                        + functionAuthProvider.get().getClass().getName()
                        + " must implement KubernetesFunctionAuthProvider");
            } else {

View on GitHub (pinned to 820761864e)

Solutions

  1. Make the configured class implement org.apache.pulsar.functions.runtime.kubernetes.KubernetesManifestCustomizer.
  2. Verify the class name in functions_worker.yml points to the Kubernetes manifest customizer, not another runtime's customizer.
  3. Check the Pulsar version docs: ensure the interface name matches the version deployed (interface has changed across releases).
  4. Rebuild/redeploy the custom NAR containing the corrected class.

Example fix

// before
public class MyCustomizer implements RuntimeCustomizer { ... }
// after
public class MyCustomizer implements KubernetesManifestCustomizer { ... }
Defensive patterns

Strategy: validation

Validate before calling

Class<?> c = Class.forName(configuredCustomizerClassName);
if (!KubernetesManifestCustomizer.class.isAssignableFrom(c)) {
    throw new IllegalArgumentException(configuredCustomizerClassName + " must implement KubernetesManifestCustomizer");
}

Type guard

boolean isValidCustomizer(Object o) { return o instanceof KubernetesManifestCustomizer; }

Try / catch

try { factory.initialize(...); } catch (IllegalArgumentException e) { if (e.getMessage().contains("KubernetesManifestCustomizer")) { log.fatal("Bad customizer config"); } throw e; }

Prevention

When it happens

Trigger: Setting the runtime customizer class name (functionRuntimeCustomizer config in functions_worker.yml) to a class that exists but implements a different customizer interface (e.g. a generic RuntimeCustomizer or wrong plugin class), causing the instanceof KubernetesManifestCustomizer check at line 232 to fail.

Common situations: Copy-pasting a customizer class name from another runtime (e.g. process/thread runtime customizer); upgrading Pulsar where the customizer interface was renamed/split; typos leading to a similarly-named wrong class; custom NAR containing an unrelated class.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/f86c758b749c922a. Report an issue: GitHub.