apache/pulsar · error · IllegalArgumentException

Only one of outputSchemaType or outputSerdeClassName should

Error message

Only one of outputSchemaType or outputSerdeClassName should be set

What it means

The function's output serialization must be declared exactly one way: outputSchemaType or outputSerdeClassName. doJavaChecks throws IllegalArgumentException when both are set, mirroring the inputSpec rule.

Source

Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java:725

                            validatableFunctionPackage.getTypePool(), false);
                }
                if (conf.getMessagePayloadProcessorConfig() != null) {
                    ValidatorUtils.validateMessagePayloadProcessor(conf.getMessagePayloadProcessorConfig(),
                            validatableFunctionPackage.getTypePool());
                }
            });
        }

        if (Void.class.equals(typeArgs[1])) {
            return new FunctionConfigUtils.ExtractedFunctionDetails(
                    functionClassName,
                    typeArgs[0].asErasure().getTypeName(),
                    typeArgs[1].asErasure().getTypeName());
        }

        // One and only one of outputSchemaType and outputSerdeClassName should be set
        if (!isEmpty(functionConfig.getOutputSerdeClassName()) && !isEmpty(functionConfig.getOutputSchemaType())) {
            throw new IllegalArgumentException(
                "Only one of outputSchemaType or outputSerdeClassName should be set");
        }

        if (!isEmpty(functionConfig.getOutputSchemaType())) {
            ValidatorUtils.validateSchema(functionConfig.getOutputSchemaType(), typeArgs[1],
                    validatableFunctionPackage.getTypePool(), false);
        }

        if (!isEmpty(functionConfig.getOutputSerdeClassName())) {
            ValidatorUtils.validateSerde(functionConfig.getOutputSerdeClassName(), typeArgs[1],
                    validatableFunctionPackage.getTypePool(), false);
        }

        if (functionConfig.getProducerConfig() != null
                && functionConfig.getProducerConfig().getCryptoConfig() != null) {
            ValidatorUtils
                    .validateCryptoKeyReader(functionConfig.getProducerConfig().getCryptoConfig(),
                            validatableFunctionPackage.getTypePool(), true);

View on GitHub (pinned to 820761864e)

Solutions

  1. Keep outputSchemaType and clear outputSerdeClassName (recommended)
  2. Or keep outputSerdeClassName and clear outputSchemaType for legacy usage
  3. Check the config after programmatic merges so only one output serializer field remains set

Example fix

// before
config.setOutputSchemaType("avro");
config.setOutputSerdeClassName("com.example.OutSerde");
// after
config.setOutputSchemaType("avro");
Defensive patterns

Strategy: validation

Validate before calling

if (notBlank(config.getOutputSerdeClassName()) && notBlank(config.getOutputSchemaType())) { throw new IllegalArgumentException("Set only one of outputSchemaType or outputSerdeClassName"); }

Type guard

boolean exclusiveOutputSerializer(FunctionConfig c) { return isBlank(c.getOutputSchemaType()) || isBlank(c.getOutputSerdeClassName()); }

Try / catch

try { ... } catch (IllegalArgumentException e) { if (e.getMessage().contains("outputSchemaType or outputSerdeClassName")) { log.error("Clear one output serializer field"); } }

Prevention

When it happens

Trigger: FunctionConfig with both setOutputSchemaType(...) and setOutputSerdeClassName(...) non-empty, usually after merging a legacy SerDe config with a schema config.

Common situations: Migration from SerDe to schema APIs; templates that set defaults for both fields; tooling that copies fields without clearing the other.

Related errors


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