{"record":{"id":"9f48c3cfdc47fb7f","repo":"pinpoint-apm/pinpoint","slug":"the-key-must-contain-key","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/RedisKVPubChannelProvider.java","lineNumber":41,"sourceCode":"import java.time.Duration;\nimport java.util.Objects;\n\n/**\n * @author youngjin.kim2\n */\nclass RedisKVPubChannelProvider implements PubChannelProvider {\n\n    private final RedisTemplate<String, String> template;\n\n    RedisKVPubChannelProvider(RedisTemplate<String, String> template) {\n        this.template = Objects.requireNonNull(template, \"template\");\n    }\n\n    @Override\n    public PubChannel getPubChannel(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 expire = Duration.parse(keyValue.getKey());\n        return new RedisKVPubChannel(this.template, expire.toMillis(), keyValue.getValue());\n    }\n\n}\n","sourceCodeStart":23,"sourceCodeEnd":48,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/redis/src/main/java/com/navercorp/pinpoint/channel/redis/kv/RedisKVPubChannelProvider.java#L23-L48","documentation":"RedisKVPubChannelProvider.getPubChannel expects pub-channel keys of the form '<duration>:<channelName>' (e.g. PT10M:myChannel), split by KeyValueTokenizer.tokenize(key, \":\"). If the key has no ':' the tokenization fails and it throws IllegalArgumentException, because the expiry Duration cannot be parsed from the key.","triggerScenarios":"Calling getPubChannel with a key lacking the ':' separator — e.g. getPubChannel(\"myChannel\") instead of getPubChannel(\"PT10M:myChannel\").","commonSituations":"Callers constructing the key from just the channel name; config where the duration prefix was dropped; refactor that changed the key format contract between producer and provider.","solutions":["Pass the key as '<ISO-8601 duration>:<channel>' — e.g. PT10M:myChannel","Add the missing ':' and Duration prefix at the call site that builds the key","Pre-check key.contains(\":\") before calling getPubChannel"],"exampleFix":"// before\nPubChannel ch = provider.getPubChannel(\"myChannel\");\n// after\nPubChannel ch = provider.getPubChannel(\"PT10M:myChannel\");","handlingStrategy":"validation","validationCode":"if (key == null || !key.contains(\":\")) {\n    throw new IllegalArgumentException(\"pub channel key must be '<duration>:<channel>'\");\n}","typeGuard":null,"tryCatchPattern":"try { PubChannel ch = provider.getPubChannel(key); } catch (IllegalArgumentException e) { log.warn(\"bad pub channel key: {}\", key); }","preventionTips":["Always build keys as '<ISO-8601 duration>:<channelName>'","Centralize key construction in one helper","Add a contains(':') assertion at key-construction sites"],"tags":["redis","pubsub","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"}