apache/pulsar · error · IllegalArgumentException
${fieldName} cannot be null
Error message
${fieldName} cannot be null What it means
IOConfigUtils.loadWithSecrets() reflects over a config class annotated with @FieldDoc to map config values. When a field is marked required=true in @FieldDoc but the provided config map contains no value (and no non-empty defaultValue), it throws IllegalArgumentException('<fieldName> cannot be null'). It is the library's declarative required-config check for Pulsar IO connectors.
Source
Thrown at pulsar-io/common/src/main/java/org/apache/pulsar/io/common/IOConfigUtils.java:87
try {
secret = secretsGetter.apply(field.getName());
} catch (Exception e) {
log.warn().attr("secret", field.getName()).exception(e)
.log("Failed to read secret");
break;
}
if (secret != null) {
configs.put(field.getName(), secret);
}
}
configs.computeIfAbsent(field.getName(), key -> {
// Use default value if it is not null before checking required
String value = fieldDoc.defaultValue();
if (value != null && !value.isEmpty()) {
return value;
}
if (fieldDoc.required()) {
throw new IllegalArgumentException(field.getName() + " cannot be null");
}
return null;
});
}
}
}
return MAPPER.convertValue(configs, clazz);
}
private static List<Field> getAllFields(Class<?> type) {
List<Field> fields = new LinkedList<>();
fields.addAll(Arrays.asList(type.getDeclaredFields()));
if (type.getSuperclass() != null) {
fields.addAll(getAllFields(type.getSuperclass()));
}
return fields;
}
}View on GitHub (pinned to 820761864e)
Solutions
- Add the missing property named exactly as the Java field to the connector config map.
- Set a @FieldDoc(defaultValue = ...) in the connector config class if a sensible default exists.
- Check that secrets injection worked so required secret-backed fields are not empty.
- Validate the config against the connector's Config class before submitting with pulsar-admin.
Example fix
// before (config submitted to pulsar-admin sinks create)
// {"topic": "persistent://public/default/in"} // missing required 'password'
// after
// {"topic": "persistent://public/default/in", "password": "${SECRETPW}"}
// or in the config class:
// @FieldDoc(required = true, defaultValue = "guest", help = "user") Defensive patterns
Strategy: validation
Validate before calling
// Validate required @FieldDoc fields before calling loadWithSecrets
for (Field f : TenantSourceConfig.class.getDeclaredFields()) {
FieldDoc doc = f.getAnnotation(FieldDoc.class);
if (doc != null && doc.required() && configMap.get(f.getName()) == null
&& (doc.defaultValue() == null || doc.defaultValue().isEmpty())) {
throw new IllegalArgumentException("Missing required config: " + f.getName());
}
} Type guard
boolean hasRequired(Map<String, Object> cfg, String key) {
Object v = cfg == null ? null : cfg.get(key);
return v instanceof String s && !s.isBlank();
} Try / catch
try {
MyConfig cfg = IOConfigUtils.loadWithSecrets(configMap, MyConfig.class, secrets);
} catch (IllegalArgumentException e) {
log.error("Connector config missing required field: {}", e.getMessage());
throw new ConnectorConfigException(e.getMessage(), e);
} Prevention
- Validate connector config against its Config class before pulsar-admin submit
- Use @FieldDoc(required=true) only where a true default doesn't exist
- Verify secret injection resolves to non-empty values in the target environment
When it happens
Trigger: Calling IOConfigUtils.loadWithSecrets(configMap, ConfigClass.class, secrets) with a map missing a field whose @FieldDoc(required=true) is set, or providing only an empty default value and no actual value.
Common situations: Submitting a Pulsar IO source/sink whose JSON/YAML config omits mandatory fields (e.g. missing password/requiredParam); environment variable or secret injection failing so the key resolves to nothing; renaming a field in config but not in the Java config class.
Related errors
- Cron Trigger is not provided with Cron String
- Timeout during mark-delete operation
- Timeout during clear backlog operation
- Timeout during skip messages operation
- Timeout during delete operation
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/c4deb2af95ccf0a7.
Report an issue: GitHub.