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; only

View on GitHub (pinned to 102af09b4a)

Solutions

  1. Pick a unique name for your layer — do not reuse an existing registered name with new parameters
  2. 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
  3. 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
  4. 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

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


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