{"record":{"id":"d5c906c0a5ea8f55","repo":"apache/pulsar","slug":"can-t-expire-message-by-time-and-by-message-positi","errorCode":null,"errorMessage":"Can't expire message by time and by message position at the same time.","messagePattern":"Can't expire message by time and by message position at the same time\\.","errorType":"validation","errorClass":"ParameterException","httpStatus":null,"severity":"warning","filePath":"pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdTopics.java","lineNumber":892,"sourceCode":"        private String subName;\n\n        @Option(names = { \"-t\", \"--expireTime\" }, description = \"Expire messages older than time in seconds \"\n                + \"(or minutes, hours, days, weeks eg: 100m, 3h, 2d, 5w)\",\n                converter = TimeUnitToSecondsConverter.class)\n        private Long expireTimeInSeconds = -1L;\n\n        @Option(names = { \"--position\",\n                \"-p\" }, description = \"message position to reset back to (ledgerId:entryId)\", required = false)\n        private String messagePosition;\n\n        @Option(names = { \"-e\", \"--exclude-reset-position\" },\n                description = \"Exclude the reset position, start consume messages from the next position.\")\n        private boolean excludeResetPosition = false;\n\n        @Override\n        void run() throws PulsarAdminException {\n            if (expireTimeInSeconds >= 0 && isNotBlank(messagePosition)) {\n                throw new ParameterException(String.format(\"Can't expire message by time and \"\n                        + \"by message position at the same time.\"));\n            }\n            String topic = validateTopicName(topicName);\n            if (expireTimeInSeconds >= 0) {\n                getTopics().expireMessages(topic, subName, expireTimeInSeconds);\n            } else if (isNotBlank(messagePosition)) {\n                int partitionIndex = TopicName.get(topic).getPartitionIndex();\n                MessageId messageId = validateMessageIdString(messagePosition, partitionIndex);\n                getTopics().expireMessages(topic, subName, messageId, excludeResetPosition);\n            } else {\n                throw new ParameterException(\n                        \"Either time (--expireTime) or message position (--position) has to be provided\"\n                                + \" to expire messages\");\n            }\n        }\n    }\n\n    @Command(description = \"Expire messages that older than given expiry time (in seconds) \"","sourceCodeStart":874,"sourceCodeEnd":910,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdTopics.java#L874-L910","documentation":"This error is thrown by the expire-messages CLI command when both --expireTime and --position are supplied. Expiring by time and by message position are mutually exclusive expiration modes, so the command rejects the combination up front via a ParameterException before any admin call is made.","triggerScenarios":"Running `pulsar-admin topics expire-messages <topic> -s <subscription> --expireTime <secs> --position <position>` — i.e. expireTimeInSeconds >= 0 AND messagePosition is non-blank.","commonSituations":"Scripted commands accumulating stale flags; users copying an example and adding --position to a time-based expire; automation templates parameterized with both values set.","solutions":["Remove either --expireTime or --position so exactly one expiration mode is given","If you want time-based expiration, drop --position; for position-based, drop --expireTime","Use -1 (or omit --expireTime) when expiring by position"],"exampleFix":"// before\npulsar-admin topics expire-messages my-topic -s sub1 --expireTime 3600 --position 10:5\n// after\npulsar-admin topics expire-messages my-topic -s sub1 --expireTime 3600","handlingStrategy":"validation","validationCode":"if (expireTime >= 0 && position != null && !position.isBlank()) {\n    throw new IllegalArgumentException(\"Provide only one of --expireTime or --position\");\n}","typeGuard":"boolean exactlyOne(Object a, Object b) {\n    boolean hasA = a != null && !(a instanceof Number n && n.longValue() < 0);\n    boolean hasB = b != null && !b.toString().isBlank();\n    return hasA ^ hasB;\n}","tryCatchPattern":"try {\n    admin.topics().expireMessages(topic, sub, expireTime);\n} catch (org.apache.pulsar.client.admin.PulsarAdminException e) {\n    log.error(\"expire-messages failed\", e);\n}","preventionTips":["Pass only one of --expireTime or --position per invocation","In scripts, guard against both variables being populated","Use -1 for expireTime when expiring by position"],"tags":["cli","parameter-validation","mutually-exclusive-flags"],"backgroundTag":"mutually-exclusive-arguments","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}