apache/pulsar · error · IllegalArgumentException

Kubernetes Secret should be a Map containing id/key pairs

Error message

Kubernetes Secret should be a Map containing id/key pairs

What it means

doAdmissionChecks requires every value in the function's secrets map to be a Map of id/key pairs. If any secret value is not a Map (e.g. a String, Number, or List), this IllegalArgumentException is thrown, since Kubernetes secret references cannot be expressed in another shape.

Source

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

            Type type = new TypeToken<Map<String, Object>>() {
            }.getType();
            Map<String, Object> secretsMap = new Gson().fromJson(functionDetails.getSecretsMap(), type);

            for (Object object : secretsMap.values()) {
                if (object instanceof Map) {
                    @SuppressWarnings("unchecked") // secret values are expected to be Map<String, String>
                    Map<String, String> kubernetesSecret = (Map<String, String>) object;
                    if (kubernetesSecret.size() < 2) {
                        throw new IllegalArgumentException("Kubernetes Secret should contain id and key");
                    }
                    if (!kubernetesSecret.containsKey(idKey)) {
                        throw new IllegalArgumentException("Kubernetes Secret should contain id information");
                    }
                    if (!kubernetesSecret.containsKey(keyKey)) {
                        throw new IllegalArgumentException("Kubernetes Secret should contain key information");
                    }
                } else {
                    throw new IllegalArgumentException("Kubernetes Secret should be a Map containing id/key pairs");
                }
            }
        }
    }
}

View on GitHub (pinned to 820761864e)

Solutions

  1. Convert each secret value to a Map with id and key fields: {"<secretId>": {"id": "<k8s-secret-name>", "key": "<key>"}}
  2. If you intend plain values, switch the worker's secretsProviderConfigurator to DefaultSecretsProviderConfigurator instead of the Kubernetes one
  3. Unquote/fix YAML so the secret entry parses as a mapping, not a scalar

Example fix

// before
secrets: {"mysecret": "db-creds"}
// after
secrets: {"mysecret": {"id": "db-creds", "key": "password"}}
Defensive patterns

Strategy: type-guard

Validate before calling

void requireSecretsAreMaps(Map<String, Object> secrets) {
    for (Map.Entry<String, Object> e : secrets.entrySet()) {
        if (!(e.getValue() instanceof Map)) {
            throw new IllegalArgumentException("Secret '" + e.getKey() + "' must be a Map of id/key pairs");
        }
    }
}

Type guard

static boolean isSecretRefMap(Object v) {
    return v instanceof Map<?, ?> m && m.containsKey("id") && m.containsKey("key");
}

Try / catch

try {
    admin.functions().createFunction(functionConfig);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("should be a Map")) { /* convert scalar secret values to {id, key} maps */ }
}

Prevention

When it happens

Trigger: Submitting a function whose secrets config contains a scalar entry, e.g. secrets: {"mysecret": "db-creds"} or a number/boolean, so the instanceof Map check fails and the else branch throws.

Common situations: using the DefaultSecretsProvider/ClearSecretsProvider syntax (plain string secret values) with KubernetesSecretsProviderConfigurator; YAML parsing a value as a scalar because of quoting; migration from another secrets provider without updating secret formats.

Related errors


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