apache/skywalking · error · IllegalArgumentException
Layer name must match [A-Z][A-Z0-9_]*: {}
Error message
Layer name must match [A-Z][A-Z0-9_]*: {} What it means
IllegalArgumentException thrown by Layer.register when the layer name is null or does not match the pattern [A-Z][A-Z0-9_]* — it must start with an uppercase letter and contain only uppercase letters, digits, and underscores. This normalizes layer naming (it is persisted and surfaced in APIs/UI) and rejects camelCase, lowercase, hyphens, spaces, or leading digits.
Source
Thrown at oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/Layer.java:356
* loaders parsing inline {@code layerDefinitions:} blocks). Idempotent on identical
* re-registration so the same extension loaded by multiple paths is harmless.
*
* @param name upper-snake-case identifier; must match {@code [A-Z][A-Z0-9_]*}
* @param value ordinal unique across all layers (see class javadoc for the ordinal
* conventions and the {@code >= 1000} recommendation for extensions)
* @param isNormal whether services in this layer are agent-installed (true) or conjectured (false)
* @return the registered layer
* @throws IllegalStateException if the registry is sealed, or on a name/ordinal conflict
* @throws IllegalArgumentException if name shape is invalid
*/
public static synchronized Layer register(final String name, final int value, final boolean isNormal) {
if (SEALED) {
throw new IllegalStateException(
"Layer registry is sealed; cannot register " + name + "=" + value
+ ". External layers must register before CoreModule.notifyAfterCompleted().");
}
if (name == null || !NAME_PATTERN.matcher(name).matches()) {
throw new IllegalArgumentException(
"Layer name must match [A-Z][A-Z0-9_]*: " + name);
}
final Layer existingByName = BY_NAME.get(name);
if (existingByName != null) {
if (existingByName.value == value && existingByName.isNormal == isNormal) {
return existingByName;
}
throw new IllegalStateException(
"Layer name conflict: " + name + " already registered as ordinal=" + existingByName.value
+ ", normal=" + existingByName.isNormal
+ "; refused re-registration as ordinal=" + value + ", normal=" + isNormal);
}
final Layer existingByValue = BY_VALUE.get(value);
if (existingByValue != null) {
throw new IllegalStateException(
"Layer ordinal conflict at " + value
+ ": existing=" + existingByValue.name + ", new=" + name);
}View on GitHub (pinned to 102af09b4a)
Solutions
- Normalize the name to upper-snake-case before registering: uppercase, replace non-alphanumerics with '_', ensure it starts with A-Z
- Validate names at config-load time and fail with a clear plugin-level message rather than deep in Layer.register
- If the name comes from external input, reject/sanitize it explicitly (e.g. name.toUpperCase(Locale.ROOT).replaceAll("[^A-Z0-9]+","_")) and ensure first char is a letter
Example fix
// before
Layer.register("my-layer", 1200, false); // hyphen -> IllegalArgumentException
// after
Layer.register("MY_LAYER", 1200, false); Defensive patterns
Strategy: validation
Validate before calling
private static final Pattern LAYER_NAME = Pattern.compile("[A-Z][A-Z0-9_]*");
String safe = raw == null ? null : raw.toUpperCase(Locale.ROOT).replaceAll("[^A-Z0-9]+", "_");
if (safe == null || !LAYER_NAME.matcher(safe).matches() || Character.isDigit(safe.charAt(0))) {
throw new IllegalArgumentException("Layer name must match [A-Z][A-Z0-9_]*: " + raw);
} Type guard
boolean isValidLayerName(String name) {
return name != null && name.matches("[A-Z][A-Z0-9_]*");
} Prevention
- Normalize external/config-sourced names to upper-snake-case before register()
- Fail fast at plugin config-load time with a clear message instead of deep in Layer.register
- Add a unit test asserting your plugin's registered layer names match the pattern
When it happens
Trigger: Calling Layer.register with names like 'myLayer', 'my-layer', 'My_Layer', '9LAYER', 'MY LAYER', or null. Common when a plugin derives the name from configuration or a protocol string without normalizing to upper-snake-case.
Common situations: Custom extension plugins taking layer names from user config or telemetry labels verbatim; porting older code that used arbitrary strings before the pattern was enforced; typos in static registrations.
Related errors
- Layer registry is sealed; cannot register {}={}. External la
- Layer name conflict: {} already registered as ordinal={}, no
- Layer ordinal conflict at {}: existing={}, new={}
- Failed to load GenAI configuration file.
- Output type {outputTypeName} has no setter {setterName}() fo
AI-assisted analysis of apache/skywalking@102af09b4a (2026-08-14).
Data as JSON: /api/errors/e74c638177ad7f40.
Report an issue: GitHub.