{"record":{"id":"a0f3b84245a18903","repo":"pinpoint-apm/pinpoint","slug":"inserted-custommetricname-is-not-valid-cause","errorCode":null,"errorMessage":"Inserted customMetricName({}) is not valid. cause:{}","messagePattern":"Inserted customMetricName\\((.+?)\\) is not valid\\. cause:(.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/monitor/metric/CustomMetricIdGenerator.java","lineNumber":87,"sourceCode":"    }\n\n    private boolean checkValidCustomMetricName(String customMetricName) {\n        try {\n            String[] split = customMetricName.split(\"/\", 3);\n\n            if (split.length != 3) {\n                throw new IllegalArgumentException(\"customMetricName must consist of {GroupName}/{MetricName}/LabelName}\");\n            }\n\n            for (String eachName : split) {\n                if (!IdValidateUtils.validateId(eachName, 64)) {\n                    return false;\n                }\n            }\n\n            return true;\n        } catch (Exception e) {\n            logger.warn(\"Inserted customMetricName({}) is not valid. cause:{}\", customMetricName, e.getMessage(), e);\n        }\n        return false;\n    }\n\n}\n","sourceCodeStart":69,"sourceCodeEnd":93,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/monitor/metric/CustomMetricIdGenerator.java#L69-L93","documentation":"Inside CustomMetricIdGenerator.checkValidCustomMetricName, the character-by-character validation loop throws (e.g. unexpected null or an unexpected runtime error while inspecting chars); the catch block logs \"Inserted customMetricName is not valid\" with the exception message and returns false. This is the exceptional path of name validation, distinct from a simple character mismatch.","triggerScenarios":"Passing a metric name that makes the validator's loop throw — most commonly a null name dereferenced via length()/charAt(), or an unexpected CharSequence implementation.","commonSituations":"Programmatically constructed counters where the name field was left null; reflection/framework-built metric objects with unset names; upgrades where the validator logic changed and older names now hit an exception path.","solutions":["Ensure the metric name is non-null and a plain String before constructing the counter.","Add a null/empty check at the call site prior to register().","Inspect the cause:{} value in the log to see the exact exception (likely NPE) and fix its source.","Upgrade Pinpoint if the validator crashes on legitimate names."],"exampleFix":"// before\nIntCounter counter = buildCounter(); // name may be null\nregistryService.register(counter);\n// after\nif (counter.getName() != null && !counter.getName().isEmpty()) {\n    registryService.register(counter);\n}","handlingStrategy":"validation","validationCode":"if (name == null || name.isEmpty()) {\n    throw new IllegalArgumentException(\"custom metric name required\");\n}","typeGuard":"boolean nonNullName(IntCounter c) { return c != null && c.getName() instanceof String; }","tryCatchPattern":"try {\n    registryService.register(counter);\n} catch (NullPointerException e) {\n    logger.warn(\"counter name was null; metric skipped\");\n}","preventionTips":["Never construct counters with null or empty names.","Validate names at object construction time in your own factory.","Check the cause:{} field in the log to find the real exception."],"tags":["metrics","null-check","validation","custom-metric"],"backgroundTag":"null-argument","analyzedSha":"744c3d3075e595656abb1ae331ad2c0e4c9eb996","analyzedAt":"2026-09-07T18:48:45.289Z","contentChangedAt":"2026-09-07T18:48:45.289Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}