provectus/kafka-ui · error · ValidationException

'className' property not set for custom serde

Error message

'className' property not set for custom serde ${serdeConfig.getName()}

What it means

Custom serdes are loaded from an external archive by class name. loadAndInitCustomSerde requires both className and filePath; when className is missing or empty it throws ValidationException indicating the custom serde cannot be resolved without it.

Solutions

  1. Add the fully-qualified className of the serde implementation to the entry
  2. Fix YAML key spelling/casing so className is actually parsed
  3. If you meant a built-in serde, use its exact built-in name instead

Example fix

// before
serde:
  - name: my-serde
    filePath: /opt/serdes/my-serde.jar
// after
serde:
  - name: my-serde
    className: com.example.MySerde
    filePath: /opt/serdes/my-serde.jar
Defensive patterns

Strategy: validation

Validate before calling

if (!isBuiltInSerdeName(cfg.getName()) && Strings.isNullOrEmpty(cfg.getClassName()))
  throw new IllegalArgumentException("custom serde " + cfg.getName() + " missing className");

Try / catch

try {
  serde = createSerdeFromConfig(cfg, ...);
} catch (ValidationException e) {
  log.error("Custom serde {}: {}", cfg.getName(), e.getMessage());
  throw e;
}

Prevention

When it happens

Trigger: A serde entry with a non-built-in name and a filePath but no className (empty/null) reaches loadAndInitCustomSerde.

Common situations: Deleting className from a copied serde template; YAML key typo (class-name vs className) so className reads as null; entry intended to be built-in but name doesn't match any built-in serde.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of provectus/kafka-ui@83b5a60cc0 (2026-09-08). Data as JSON: /api/errors/aa455c27d1a16360. Report an issue: GitHub.

Appendix: source

Thrown at kafka-ui-api/src/main/java/com/provectus/kafka/ui/serdes/SerdesInitializer.java:259

        serdeConfig.getName(),
        serde,
        nullablePattern(serdeConfig.getTopicKeysPattern()),
        nullablePattern(serdeConfig.getTopicValuesPattern()),
        null
    );
  }

  @SneakyThrows
  private <T extends Serde> T createSerdeInstance(Class<T> clazz) {
    return clazz.getDeclaredConstructor().newInstance();
  }

  private SerdeInstance loadAndInitCustomSerde(SerdeConfig serdeConfig,
                                               PropertyResolver serdeProps,
                                               PropertyResolver clusterProps,
                                               PropertyResolver globalProps) {
    if (Strings.isNullOrEmpty(serdeConfig.getClassName())) {
      throw new ValidationException(
          "'className' property not set for custom serde " + serdeConfig.getName());
    }
    if (Strings.isNullOrEmpty(serdeConfig.getFilePath())) {
      throw new ValidationException(
          "'filePath' property not set for custom serde " + serdeConfig.getName());
    }
    var loaded = customSerdeLoader.loadAndConfigure(
        serdeConfig.getClassName(), serdeConfig.getFilePath(), serdeProps, clusterProps, globalProps);
    return new SerdeInstance(
        serdeConfig.getName(),
        loaded.getSerde(),
        nullablePattern(serdeConfig.getTopicKeysPattern()),
        nullablePattern(serdeConfig.getTopicValuesPattern()),
        loaded.getClassLoader()
    );
  }

  @Nullable

View on GitHub (pinned to 83b5a60cc0)