apache/skywalking · critical · ModuleStartException
LAL rule '{}' declares outputType '{}' but neither a registe
Error message
LAL rule '{}' declares outputType '{}' but neither a registered LALOutputBuilder name nor a class was found. What it means
Thrown when a LAL rule's outputType: value cannot be resolved: if it contains no dot it is first treated as a registered LALOutputBuilder short name (discovered via ServiceLoader); otherwise/afterwards it is tried as an FQCN via Class.forName(). When both fail — unknown short name and unloadable class — compilation aborts. outputType selects the AbstractLog subclass the rule's sink builds.
Source
Thrown at oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/provider/log/listener/LogFilterListener.java:545
private static Class<?> resolveOutputType(
final LALConfig config,
final LALSourceTypeProvider spiProvider) throws ModuleStartException {
// Per-rule YAML config takes priority
final String yamlType = config.getOutputType();
if (yamlType != null && !yamlType.isEmpty()) {
// Try short name first (no '.' means it's not a FQCN)
if (!yamlType.contains(".")) {
final Class<?> byName = loadOutputBuilderNames().get(yamlType);
if (byName != null) {
return byName;
}
}
// Fall back to FQCN
try {
return Class.forName(yamlType);
} catch (ClassNotFoundException e) {
throw new ModuleStartException(
"LAL rule '" + config.getName() + "' declares outputType '"
+ yamlType + "' but neither a registered LALOutputBuilder name"
+ " nor a class was found.", e);
}
}
// Fall back to SPI default for the layer
if (spiProvider != null) {
final Class<?> spiOutput = spiProvider.outputType();
if (spiOutput != null) {
return spiOutput;
}
}
return null; // DSL.of() will default to Log.class
}
@Override
public LogAnalysisListener create(Layer layer) {
// Snapshot the suspended set once so a concurrent suspend/resume can't flip behaviourView on GitHub (pinned to 102af09b4a)
Solutions
- Use the exact registered short name of an LALOutputBuilder SPI implementation (check META-INF/services entries)
- Or use the fully-qualified class name of an AbstractLog subclass that is on the classpath
- Ship the jar containing the output class/builder into oap-libs
- Omit outputType to use the layer's SPI default or the built-in Log output
Example fix
# before outputType: mylog # after (either form) outputType: com.mycompany.log.MyLogOutput
Defensive patterns
Strategy: validation
Validate before calling
// Pre-deploy outputType resolution mirror:
Class<?> resolve(String v, Map<String, Class<?>> spiNames) throws Exception {
if (!v.contains(".")) {
Class<?> c = spiNames.get(v);
if (c != null) return c;
}
return Class.forName(v); // throws -> rule would fail at boot
} Try / catch
try {
Class<?> out = resolveOutputType(config, spiProvider);
} catch (ModuleStartException e) {
// fix the short name (must match an LALOutputBuilder registration) or use a valid FQCN
} Prevention
- Register custom output builders in META-INF/services and use the exact short name
- Ship the output jar with the OAP distribution
- Omit outputType to inherit the layer default when unsure
When it happens
Trigger: outputType: my-log with no LALOutputBuilder SPI registered under that short name and no class named my-log; an FQCN whose jar is not on the classpath; casing/typo in either form.
Common situations: Writing a custom output entity but forgetting the META-INF/services registration for the builder; deploying the rule without the custom output jar; renaming the output class without updating rules.
Related errors
- LALSourceTypeProvider {} for layer {} declared inputType {}
- LAL rule '{}' declares inputType '{}' but the class was not
- tag() reads LogData tags but the input type is {inputTypeNam
- sourceAttribute() requires exactly one string literal argume
- Cannot resolve {desc} — no matching codegen path. Parser typ
AI-assisted analysis of apache/skywalking@102af09b4a (2026-08-14).
Data as JSON: /api/errors/af8a7f37424ac5a5.
Report an issue: GitHub.