{"record":{"id":"a1a5c8974cf7ab87","repo":"pinpoint-apm/pinpoint","slug":"the-key-must-contain-key-a1a5c8","errorCode":null,"errorMessage":"the key must contain ':' key:","messagePattern":"the key must contain ':' key:","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"redis/src/main/java/com/navercorp/pinpoint/channel/redis/kv/RedisKVSubChannelProvider.java","lineNumber":44,"sourceCode":"\n/**\n * @author youngjin.kim2\n */\nclass RedisKVSubChannelProvider implements SubChannelProvider {\n\n    private final RedisTemplate<String, String> template;\n    private final Scheduler scheduler;\n\n    RedisKVSubChannelProvider(RedisTemplate<String, String> template, Scheduler scheduler) {\n        this.template = Objects.requireNonNull(template, \"template\");\n        this.scheduler = Objects.requireNonNull(scheduler, \"scheduler\");\n    }\n\n    @Override\n    public SubChannel getSubChannel(String key) {\n        KeyValueTokenizer.KeyValue keyValue = KeyValueTokenizer.tokenize(key, \":\");\n        if (keyValue == null) {\n            throw new IllegalArgumentException(\"the key must contain ':' key:\" + key);\n        }\n        Duration period = Duration.parse(keyValue.getKey());\n        return new RedisKVSubChannel(this.template, this.scheduler, period, keyValue.getValue());\n    }\n\n}\n","sourceCodeStart":26,"sourceCodeEnd":51,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/redis/src/main/java/com/navercorp/pinpoint/channel/redis/kv/RedisKVSubChannelProvider.java#L26-L51","documentation":"RedisKVSubChannelProvider.getSubChannel requires keys of the form '<duration>:<value>' because KeyValueTokenizer.tokenize(key, \":\") must yield both a key (parsed with Duration.parse) and a value. When no ':' is present, tokenize returns null and an IllegalArgumentException is thrown. The duration portion must also be a valid ISO-8601 duration (e.g. PT1S).","triggerScenarios":"Calling getSubChannel with a string lacking a ':' separator, e.g. getSubChannel(\"PT30S\") or getSubChannel(\"mykey\").","commonSituations":"Configuration or code that constructs subscription keys from a single value, forgetting the '<ISO-duration>:<key>' format; refactors that changed the key format; passing a bare channel name from older Pinpoint versions.","solutions":["Format the key as an ISO-8601 duration followed by ':' and the key name, e.g. \"PT30S:mykey\".","Ensure the segment before ':' is Duration.parse-compatible (PT10S, PT1M, ...) or a Duration.parse exception follows.","If the key comes from external config, add a format check before calling getSubChannel."],"exampleFix":"// before\nprovider.getSubChannel(\"mykey\");\n// after\nprovider.getSubChannel(\"PT30S:mykey\");","handlingStrategy":"validation","validationCode":"if (key == null || !key.contains(\":\")) throw new IllegalArgumentException(\"key must be '<ISO-duration>:<name>'\");\nDuration.parse(key.substring(0, key.indexOf(':'))); // validates duration part","typeGuard":null,"tryCatchPattern":"try { provider.getSubChannel(key); } catch (IllegalArgumentException e) { /* fix key format / alert config error */ }","preventionTips":["Always build keys from a helper that joins Duration.toString() and the key name with ':'","Validate externally supplied keys before calling getSubChannel"],"tags":["redis","illegal-argument","key-format"],"backgroundTag":"invalid-argument-format","analyzedSha":"744c3d3075e595656abb1ae331ad2c0e4c9eb996","analyzedAt":"2026-09-07T18:48:45.289Z","contentChangedAt":"2026-09-07T18:48:45.289Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}