apache/skywalking · critical · IllegalStateException
Layer name conflict: {} already registered as ordinal={}, no
Error message
Layer name conflict: {} already registered as ordinal={}, normal={}; refused re-registration as ordinal={}, normal={} What it means
IllegalStateException thrown by Layer.register when the layer name is already registered with a DIFFERENT ordinal or isNormal flag. Re-registration with identical name+value+isNormal is an idempotent no-op (returns the existing layer), but any mismatch is treated as a bug: stored data keys off the ordinal, so silently remapping a name to a new number would corrupt interpretation of persisted telemetry.
Source
Thrown at oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/Layer.java:364
* @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);
}
final Layer layer = new Layer(name, value, isNormal);
BY_VALUE.put(value, layer);
BY_NAME.put(name, layer);
return layer;
}
/**
* Closes the registry. Subsequent {@link #register} calls throw; onlyView on GitHub (pinned to 102af09b4a)
Solutions
- Pick a unique name for your layer — do not reuse an existing registered name with new parameters
- Keep a single canonical registration site (one static constant in one class) so the same plugin loaded by multiple paths hits the idempotent identical-registration branch
- If you intended to change the ordinal, that is a data-compat break: use a NEW name and leave the old layer alone, or migrate stored data deliberately
- Check the message: it prints both the existing ordinal/normal and your attempted values — align or rename accordingly
Example fix
// before
Layer.register("E2E", 1200, false); // core already has E2E at another ordinal -> throws
// after
Layer.register("MY_E2E", 1200, false); // unique name, no conflict Defensive patterns
Strategy: validation
Validate before calling
Optional<Layer> existing = Layer.fromName(name); // or equivalent lookup
if (existing.isPresent() && (existing.get().value() != value || existing.get().isNormal() != isNormal)) {
throw new IllegalStateException("Layer " + name + " already registered with different params; pick a new name");
}
Layer.register(name, value, isNormal); // safe: identical registration is idempotent Try / catch
try {
Layer.register(name, value, isNormal);
} catch (IllegalStateException e) {
if (e.getMessage().contains("name conflict")) {
// reuse the existing layer instead of re-registering with new params
return Layer.fromName(name).orElseThrow(() -> e);
}
throw e;
} Prevention
- Keep exactly one static registration constant per layer in one canonical class so duplicate loads are identical (idempotent)
- Never change a shipped layer's ordinal or isNormal — add a new layer name instead
- Audit oap-libs for duplicate copies of extension jars that may register divergent parameters
- Namespace third-party layer names with a prefix (e.g. VENDOR_*) to avoid collisions
When it happens
Trigger: Two plugins (or two versions of one plugin) registering the same name with different ordinals, e.g. Layer.register("CUSTOM", 1200, false) after the core/another extension already registered CUSTOM=1100; also flipping isNormal between registrations.
Common situations: Copying a sample extension and keeping its layer name while changing the recommended ordinal; a plugin upgraded to use a new ordinal while a fork/second copy with the old ordinal is still on the classpath; duplicated extension jars in oap-libs producing double registration with drift.
Related errors
- Layer ordinal conflict at {}: existing={}, new={}
- Layer registry is sealed; cannot register {}={}. External la
- Layer name must match [A-Z][A-Z0-9_]*: {}
- Failed to compile hierarchy rule: {name}, expression: {expre
- Hierarchy rule parsing failed: {errors} in expression: {expr
AI-assisted analysis of apache/skywalking@102af09b4a (2026-08-14).
Data as JSON: /api/errors/c8998dffa41c9464.
Report an issue: GitHub.