apache/pulsar · error · RuntimeException

No FunctionContainer found

Error message

No FunctionContainer found

What it means

KubernetesSecretsProviderConfigurator.configureKubernetesRuntimeSecretsProvider() scans the function pod spec's containers for one named functionsContainerName (typically 'function'). If no container matches after the loop, it throws RuntimeException("No FunctionContainer found") because it cannot attach secret env vars to the pod spec.

Source

Thrown at pulsar-functions/secrets/src/main/java/org/apache/pulsar/functions/secretsproviderconfigurator/KubernetesSecretsProviderConfigurator.java:83

    }

    // Kubernetes secrets can be exposed as volume mounts or as
    // environment variables in the pods. We are currently using the
    // environment variables way. Essentially the secretName/secretPath
    // is attached as secretRef to the environment variables
    // of a pod and kubernetes magically makes the secret pointed to by this combination available as a env variable.
    @Override
    public void configureKubernetesRuntimeSecretsProvider(V1PodSpec podSpec, String functionsContainerName,
                                                          FunctionDetails functionDetails) {
        V1Container container = null;
        for (V1Container v1Container : podSpec.getContainers()) {
            if (v1Container.getName().equals(functionsContainerName)) {
                container = v1Container;
                break;
            }
        }
        if (container == null) {
            throw new RuntimeException("No FunctionContainer found");
        }
        if (!StringUtils.isEmpty(functionDetails.getSecretsMap())) {
            Type type = new TypeToken<Map<String, Object>>() {
            }.getType();
            Map<String, Object> secretsMap = new Gson().fromJson(functionDetails.getSecretsMap(), type);
            for (Map.Entry<String, Object> entry : secretsMap.entrySet()) {
                final V1EnvVar secretEnv = new V1EnvVar();
                @SuppressWarnings("unchecked") // secret values are expected to be Map<String, String>
                Map<String, String> kv = (Map<String, String>) entry.getValue();
                secretEnv.name(entry.getKey())
                        .valueFrom(new V1EnvVarSource()
                                .secretKeyRef(new V1SecretKeySelector()
                                        .name(kv.get(idKey))
                                        .key(kv.get(keyKey))));
                container.addEnvItem(secretEnv);
            }
        }
    }

View on GitHub (pinned to 820761864e)

Solutions

  1. Ensure the function pod spec includes a container named 'function' (the default functionsContainerName), or update functionsContainerName in the worker's KubernetesRuntimeFactory config to match your custom container name.
  2. Remove/fix custom pod.yaml templates that rename the container.
  3. Check function worker config (k8s runtime settings) so the container name matches between pod creation and secrets configuration.
  4. Inspect the generated pod spec (kubectl get pod -o jsonpath='{.spec.containers[*].name}') to confirm names.

Example fix

// before (custom pod template)
containers:
  - name: my-fn-container
    image: ...
// after
containers:
  - name: function
    image: ...
Defensive patterns

Strategy: validation

Validate before calling

boolean hasFunctionContainer = java.util.Arrays.stream(podSpec.getContainers())
  .anyMatch(c -> c.getName().equals("function"));
if (!hasFunctionContainer) throw new IllegalStateException("Pod spec must contain a container named 'function'");

Type guard

boolean podHasFunctionContainer(io.kubernetes.client.openapi.models.V1PodSpec spec, String name) {
  return spec != null && spec.getContainers() != null
    && spec.getContainers().stream().anyMatch(c -> name.equals(c.getName()));
}

Try / catch

try { configurator.configureKubernetesRuntimeSecretsProvider(functionDetails, podSpec, containerName); } catch (RuntimeException e) { if ("No FunctionContainer found".equals(e.getMessage())) { log.error("Pod containers: {}", java.util.Arrays.toString(podSpec.getContainers().stream().map(c -> c.getName()).toArray())); } throw e; }

Prevention

When it happens

Trigger: Submitting/configuring a function on Kubernetes where the generated (or provided) pod spec has no container literally named after functionsContainerName — e.g. custom pod specs renamed the container, or the function worker built the pod without the expected 'function' container.

Common situations: Customized KubernetesRuntimeFactory container names; user-supplied pod templates overriding the container name; version changes where the default container name changed; mutating webhooks rewriting container names.

Related errors


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