{"id":"d9c91a62c758630a","repo":"apache/kafka","slug":"did-not-recognize-recording-level-configid","errorCode":null,"errorMessage":"Did not recognize recording level {configId}","messagePattern":"Did not recognize recording level (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/common/metrics/Sensor.java","lineNumber":132,"sourceCode":"                throw new IllegalArgumentException(String.format(\"Unexpected RecordLevel id `%d`, it should be between `%d` \" +\n                    \"and `%d` (inclusive)\", id, MIN_RECORDING_LEVEL_KEY, MAX_RECORDING_LEVEL_KEY));\n            return ID_TO_TYPE[id];\n        }\n\n        /** Case insensitive lookup by protocol name */\n        public static RecordingLevel forName(String name) {\n            return RecordingLevel.valueOf(name.toUpperCase(Locale.ROOT));\n        }\n\n        public boolean shouldRecord(final int configId) {\n            if (configId == INFO.id) {\n                return this.id == INFO.id;\n            } else if (configId == DEBUG.id) {\n                return this.id == INFO.id || this.id == DEBUG.id;\n            } else if (configId == TRACE.id) {\n                return true;\n            } else {\n                throw new IllegalStateException(\"Did not recognize recording level \" + configId);\n            }\n        }\n    }\n\n    private final RecordingLevel recordingLevel;\n\n    Sensor(Metrics registry, String name, Sensor[] parents, MetricConfig config, Time time,\n           long inactiveSensorExpirationTimeSeconds, RecordingLevel recordingLevel) {\n        super();\n        this.registry = registry;\n        this.name = Objects.requireNonNull(name);\n        this.parents = parents == null ? new Sensor[0] : parents;\n        this.metrics = new LinkedHashMap<>();\n        this.stats = new ArrayList<>();\n        this.config = config;\n        this.time = time;\n        this.inactiveSensorExpirationTimeMs = TimeUnit.MILLISECONDS.convert(inactiveSensorExpirationTimeSeconds, TimeUnit.SECONDS);\n        this.lastRecordTime = time.milliseconds();","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/metrics/Sensor.java#L114-L150","documentation":"Thrown by RecordingLevel.shouldRecord(int configId) when configId does not equal INFO.id, DEBUG.id, or TRACE.id. Unlike forId, this is an IllegalStateException because shouldRecord is given a configId that the enum switch cannot match, which the code treats as an impossible/internal-consistency condition rather than user input. It guards the metric-recording gating logic that decides whether a sensor emits at the configured verbosity.","triggerScenarios":"A Sensor's shouldRecord() is invoked when the configured MetricConfig.recordLevel().id is not 0, 1, or 2. Because shouldRecord(configId) only has explicit branches for INFO/DEBUG/TRACE ids, any other numeric configId (negative, or > 2) lands in the else branch.","commonSituations":"A custom or mock MetricConfig returning a fabricated recordLevel id; memory corruption or uninitialized config in a test; a future RecordingLevel id added to the enum but the switch in shouldRecord not updated; deserialized config whose recordLevel was read with the wrong type width.","solutions":["Ensure MetricConfig.recordLevel() always returns a RecordingLevel obtained from RecordingLevel.forName / RecordingLevel.forId, never a hand-built id.","If you build MetricConfig in tests, set the recordLevel from the enum constant (e.g. RecordingLevel.INFO) rather than poking an id field.","When extending RecordingLevel with a new level, add the matching branch to shouldRecord so the new id is recognized.","Add a guard before calling shouldRecord to validate the configured id is within [0, MAX_RECORDING_LEVEL_KEY]."],"exampleFix":"// before\nMetricConfig cfg = new MetricConfig().recordLevel(/* raw int */ 5);\n\n// after\nMetricConfig cfg = new MetricConfig().recordLevel(RecordingLevel.DEBUG);","handlingStrategy":"validation","validationCode":"int configId = /* from wire/config */;\nif (configId != Sensor.RecordingLevel.INFO.id\n        && configId != Sensor.RecordingLevel.DEBUG.id\n        && configId != Sensor.RecordingLevel.TRACE.id) {\n    // unknown recording level; do not call shouldRecord(configId)\n    throw new IllegalArgumentException(\"Unknown recording level configId: \" + configId);\n}","typeGuard":"static boolean isKnownRecordingLevelConfigId(int configId) {\n    return configId == Sensor.RecordingLevel.INFO.id\n        || configId == Sensor.RecordingLevel.DEBUG.id\n        || configId == Sensor.RecordingLevel.TRACE.id;\n}","tryCatchPattern":null,"preventionTips":["Only ever pass ids taken from the Sensor.RecordingLevel enum constants.","Never invent configId values; they must match an existing RecordingLevel.id exactly.","If you hit this in production, suspect version skew between client and broker recording levels."],"tags":["metrics","internal-consistency","configuration","recording-level"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}