{"record":{"id":"e74c638177ad7f40","repo":"apache/skywalking","slug":"layer-name-must-match-a-z-a-z0-9","errorCode":null,"errorMessage":"Layer name must match [A-Z][A-Z0-9_]*: {}","messagePattern":"Layer name must match \\[A-Z\\]\\[A-Z0-9_\\]\\*: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/Layer.java","lineNumber":356,"sourceCode":"     * loaders parsing inline {@code layerDefinitions:} blocks). Idempotent on identical\n     * re-registration so the same extension loaded by multiple paths is harmless.\n     *\n     * @param name    upper-snake-case identifier; must match {@code [A-Z][A-Z0-9_]*}\n     * @param value   ordinal unique across all layers (see class javadoc for the ordinal\n     *                conventions and the {@code >= 1000} recommendation for extensions)\n     * @param isNormal whether services in this layer are agent-installed (true) or conjectured (false)\n     * @return the registered layer\n     * @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        }","sourceCodeStart":338,"sourceCodeEnd":374,"githubUrl":"https://github.com/apache/skywalking/blob/102af09b4a56064e22050dded10e2c52e490d040/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/Layer.java#L338-L374","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nLayer.register(\"my-layer\", 1200, false); // hyphen -> IllegalArgumentException\n\n// after\nLayer.register(\"MY_LAYER\", 1200, false);","handlingStrategy":"validation","validationCode":"private static final Pattern LAYER_NAME = Pattern.compile(\"[A-Z][A-Z0-9_]*\");\nString safe = raw == null ? null : raw.toUpperCase(Locale.ROOT).replaceAll(\"[^A-Z0-9]+\", \"_\");\nif (safe == null || !LAYER_NAME.matcher(safe).matches() || Character.isDigit(safe.charAt(0))) {\n    throw new IllegalArgumentException(\"Layer name must match [A-Z][A-Z0-9_]*: \" + raw);\n}","typeGuard":"boolean isValidLayerName(String name) {\n    return name != null && name.matches(\"[A-Z][A-Z0-9_]*\");\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["layer-registry","validation","naming","oap-server"],"backgroundTag":null,"analyzedSha":"102af09b4a56064e22050dded10e2c52e490d040","analyzedAt":"2026-08-14T10:47:52.647Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}