apache/skywalking · critical · IllegalStateException

LALSourceTypeProvider {} for layer {} declared inputType {}

Error message

LALSourceTypeProvider {} for layer {} declared inputType {} — LAL accepts only LogData / LogData.Builder (default agent path), a protobuf Message subclass, or a type implementing {}. Update the provider's inputType() or implement ToJson on {}.

What it means

Thrown when validating a LALSourceTypeProvider SPI implementation whose inputType() returns a class outside the accepted contract: LogData/LogData.Builder, a protobuf Message/Message.Builder, or anything implementing ToJson. The check exists because the codegen must know how to surface the input to the rule — typed getter access for protos, JSON conversion via ToJson, or the LogData path. It is an IllegalStateException during provider/rule wiring.

Source

Thrown at oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/provider/log/listener/LogFilterListener.java:474

         * (custom POJO inputs). A provider that declares an out-of-family
         * {@code inputType()} will fail downstream dispatch (the framework
         * fallback {@code (LogData.Builder)} cast throws ClassCastException at
         * runtime), so we surface the contract violation here at startup with a
         * pointer at the SPI rather than letting it leak into the receiver hot path.
         */
        private static void validateInputTypeContract(final LALSourceTypeProvider provider) {
            final Class<?> inputType = provider.inputType();
            if (inputType == null) {
                return;
            }
            if (LogData.class.isAssignableFrom(inputType)
                || LogData.Builder.class.isAssignableFrom(inputType)
                || Message.class.isAssignableFrom(inputType)
                || Message.Builder.class.isAssignableFrom(inputType)
                || ToJson.class.isAssignableFrom(inputType)) {
                return;
            }
            throw new IllegalStateException(
                "LALSourceTypeProvider " + provider.getClass().getName() + " for layer "
                    + provider.layer() + " declared inputType " + inputType.getName()
                    + " — LAL accepts only LogData / LogData.Builder (default agent path), "
                    + "a protobuf Message subclass, or a type implementing "
                    + ToJson.class.getName() + ". Update the provider's inputType() or "
                    + "implement ToJson on " + inputType.getName() + ".");
        }

        private static Class<?> resolveInputType(final LALConfig config,
                                                  final LALSourceTypeProvider spiProvider) throws ModuleStartException {
            final String yamlType = config.getInputType();
            if (yamlType != null && !yamlType.isEmpty()) {
                try {
                    return Class.forName(yamlType);
                } catch (ClassNotFoundException e) {
                    throw new ModuleStartException(
                        "LAL rule '" + config.getName() + "' declares inputType '"
                            + yamlType + "' but the class was not found.", e);

View on GitHub (pinned to 102af09b4a)

Solutions

  1. Implement ToJson on your input class (simplest for POJOs — LAL converts it to a parsed map)
  2. Or make the input a protobuf Message and return that from inputType()
  3. Or return null from inputType() to fall back to the LogMetadata default path
  4. Register the corrected provider in META-INF/services and rebuild

Example fix

// before
public class MyProvider implements LALSourceTypeProvider {
    public Class<?> inputType() { return MyPojo.class; }
}

// after
public class MyPojo implements ToJson { ... }
public class MyProvider implements LALSourceTypeProvider {
    public Class<?> inputType() { return MyPojo.class; }
}
Defensive patterns

Strategy: type-guard

Validate before calling

// SPI self-check a provider can run in tests:
Class<?> t = provider.inputType();
boolean ok = t == null
    || LogData.class.isAssignableFrom(t)
    || LogData.Builder.class.isAssignableFrom(t)
    || com.google.protobuf.Message.class.isAssignableFrom(t)
    || com.google.protobuf.Message.Builder.class.isAssignableFrom(t)
    || ToJson.class.isAssignableFrom(t);
if (!ok) throw new IllegalStateException("inputType contract violated: " + t);

Type guard

boolean isValidLalInputType(Class<?> t) {
    return t == null
        || LogData.class.isAssignableFrom(t)
        || LogData.Builder.class.isAssignableFrom(t)
        || Message.class.isAssignableFrom(t)
        || Message.Builder.class.isAssignableFrom(t)
        || ToJson.class.isAssignableFrom(t);
}

Prevention

When it happens

Trigger: A receiver plugin implements LALSourceTypeProvider and returns a plain POJO class from inputType() that is neither a protobuf Message nor ToJson; returning a collection/Map/record type; generics erased types.

Common situations: Writing a custom log receiver and its LAL source provider; porting a v1 provider that had no type contract; returning a DTO class and forgetting the ToJson adapter.

Related errors


AI-assisted analysis of apache/skywalking@102af09b4a (2026-08-14). Data as JSON: /api/errors/6e1e9a3016fafdb8. Report an issue: GitHub.