{"record":{"id":"c8998dffa41c9464","repo":"apache/skywalking","slug":"layer-name-conflict-already-registered-as-ordi","errorCode":null,"errorMessage":"Layer name conflict: {} already registered as ordinal={}, normal={}; refused re-registration as ordinal={}, normal={}","messagePattern":"Layer name conflict: (.+?) already registered as ordinal=(.+?), normal=(.+?); refused re-registration as ordinal=(.+?), normal=(.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"critical","filePath":"oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/Layer.java","lineNumber":364,"sourceCode":"     * @throws IllegalStateException     if the registry is sealed, or on a name/ordinal conflict\n     * @throws IllegalArgumentException  if name shape is invalid\n     */\n    public static synchronized Layer register(final String name, final int value, final boolean isNormal) {\n        if (SEALED) {\n            throw new IllegalStateException(\n                \"Layer registry is sealed; cannot register \" + name + \"=\" + value\n                    + \". External layers must register before CoreModule.notifyAfterCompleted().\");\n        }\n        if (name == null || !NAME_PATTERN.matcher(name).matches()) {\n            throw new IllegalArgumentException(\n                \"Layer name must match [A-Z][A-Z0-9_]*: \" + name);\n        }\n        final Layer existingByName = BY_NAME.get(name);\n        if (existingByName != null) {\n            if (existingByName.value == value && existingByName.isNormal == isNormal) {\n                return existingByName;\n            }\n            throw new IllegalStateException(\n                \"Layer name conflict: \" + name + \" already registered as ordinal=\" + existingByName.value\n                    + \", normal=\" + existingByName.isNormal\n                    + \"; refused re-registration as ordinal=\" + value + \", normal=\" + isNormal);\n        }\n        final Layer existingByValue = BY_VALUE.get(value);\n        if (existingByValue != null) {\n            throw new IllegalStateException(\n                \"Layer ordinal conflict at \" + value\n                    + \": existing=\" + existingByValue.name + \", new=\" + name);\n        }\n        final Layer layer = new Layer(name, value, isNormal);\n        BY_VALUE.put(value, layer);\n        BY_NAME.put(name, layer);\n        return layer;\n    }\n\n    /**\n     * Closes the registry. Subsequent {@link #register} calls throw; only","sourceCodeStart":346,"sourceCodeEnd":382,"githubUrl":"https://github.com/apache/skywalking/blob/102af09b4a56064e22050dded10e2c52e490d040/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/Layer.java#L346-L382","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nLayer.register(\"E2E\", 1200, false); // core already has E2E at another ordinal -> throws\n\n// after\nLayer.register(\"MY_E2E\", 1200, false); // unique name, no conflict","handlingStrategy":"validation","validationCode":"Optional<Layer> existing = Layer.fromName(name); // or equivalent lookup\nif (existing.isPresent() && (existing.get().value() != value || existing.get().isNormal() != isNormal)) {\n    throw new IllegalStateException(\"Layer \" + name + \" already registered with different params; pick a new name\");\n}\nLayer.register(name, value, isNormal); // safe: identical registration is idempotent","typeGuard":null,"tryCatchPattern":"try {\n    Layer.register(name, value, isNormal);\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"name conflict\")) {\n        // reuse the existing layer instead of re-registering with new params\n        return Layer.fromName(name).orElseThrow(() -> e);\n    }\n    throw e;\n}","preventionTips":["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"],"tags":["layer-registry","conflict","plugin-development","oap-server"],"backgroundTag":null,"analyzedSha":"102af09b4a56064e22050dded10e2c52e490d040","analyzedAt":"2026-08-14T10:47:52.647Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}