{"record":{"id":"1becbb88ab3b6df2","repo":"apache/kafka","slug":"cannot-lose-partitions-that-are-not-currently-assi","errorCode":null,"errorMessage":"Cannot lose partitions that are not currently assigned: {notAssigned}","messagePattern":"Cannot lose partitions that are not currently assigned: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/consumer/MockConsumer.java","lineNumber":172,"sourceCode":"     * Simulates a partition loss event. Calls {@link ConsumerRebalanceListener#onPartitionsLost}\n     * for the specified partitions and removes them from the current assignment. Unlike\n     * {@link #rebalance(Collection)}, which calls {@link ConsumerRebalanceListener#onPartitionsRevoked},\n     * this method models the case where the consumer loses partitions without a graceful revoke..\n     *\n     * <p>Only records belonging to the lost partitions are cleared; records for retained\n     * partitions are unaffected.\n     *\n     * @param partitionsLost the partitions to lose; all must be currently assigned\n     * @throws IllegalStateException if any partition is not currently assigned\n     */\n    public synchronized void losePartitions(Collection<TopicPartition> partitionsLost) {\n        Set<TopicPartition> currentAssignment = this.subscriptions.assignedPartitions();\n        Set<TopicPartition> lost = new HashSet<>(partitionsLost);\n        List<TopicPartition> notAssigned = lost.stream()\n            .filter(tp -> !currentAssignment.contains(tp))\n            .collect(Collectors.toList());\n        if (!notAssigned.isEmpty())\n            throw new IllegalStateException(\"Cannot lose partitions that are not currently assigned: \" + notAssigned);\n        lost.forEach(records::remove);\n        this.subscriptions.onPartitionsLost(lost);\n        Set<TopicPartition> remaining = currentAssignment.stream()\n            .filter(tp -> !lost.contains(tp))\n            .collect(Collectors.toSet());\n        this.subscriptions.assignFromSubscribed(remaining);\n    }\n\n    @Override\n    public synchronized Set<String> subscription() {\n        return subscriptions.subscription();\n    }\n\n    @Override\n    public synchronized void subscribe(Collection<String> topics) {\n        subscribeInternal(topics, null);\n    }\n","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/apache/kafka/blob/996fb4585aa1bcc8980b0e1b8d6b168b986cd979/clients/src/main/java/org/apache/kafka/clients/consumer/MockConsumer.java#L154-L190","documentation":"Thrown by MockConsumer.losePartitions when one or more of the requested partitions is not in the current assignment. MockConsumer simulates rebalance events for tests; losing a partition that was never assigned would put the mock in an inconsistent state, so the call is rejected wholesale. The message lists exactly which partitions are not assigned.","triggerScenarios":"In a unit test, calling losePartitions with a TopicPartition you never assigned via assign() or rebalance; calling losePartitions twice for the same partition; mismatched partition numbers between assign and lose.","commonSituations":"Test scaffolding where the assigned set and the lost set are computed by different helpers; refactor that changed partition counts; copy-paste of a test that used a different topic name.","solutions":["Verify partitionsLost is a subset of mock.subscription()/assignedPartitions() before calling losePartits; assert in the test setup.","Call mock.assign(...) (or schedule rebalance) first so the partitions are in the assignment.","Drop the offending TopicPartition from the lost set or re-derive it from the current assignment."],"exampleFix":"// before\nmockConsumer.assign(Set.of(new TopicPartition(\"orders\", 0)));\nmockConsumer.losePartitions(Set.of(new TopicPartition(\"orders\", 1))); // not assigned\n\n// after\nTopicPartition tp0 = new TopicPartition(\"orders\", 0);\nmockConsumer.assign(Set.of(tp0));\nmockConsumer.losePartitions(Set.of(tp0));","handlingStrategy":"validation","validationCode":"Set<TopicPartition> assigned = mockConsumer.assignment();\nList<TopicPartition> invalid = partitionsLost.stream()\n    .filter(tp -> !assigned.contains(tp)).collect(Collectors.toList());\nif (!invalid.isEmpty()) throw new IllegalStateException(\"Cannot lose unassigned: \" + invalid);\nmockConsumer.losePartitions(partitionsLost);","typeGuard":"static boolean allAssigned(MockConsumer<?,?> m, Collection<TopicPartition> tps) {\n    Set<TopicPartition> a = m.assignment();\n    return tps.stream().allMatch(a::contains);\n}","tryCatchPattern":"try {\n    mockConsumer.losePartitions(toLose);\n} catch (IllegalStateException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Cannot lose partitions that are not currently assigned\")) {\n        // recompute toLose as the intersection with current assignment, then retry once\n    }\n    throw e;\n}","preventionTips":["In test helpers, intersect the lost set with mock.assignment() before calling losePartitions.","Derive partition references from a shared constant set used for assign and lose.","Add assertions on assignment state before each rebalance step."],"tags":["consumer","mock-consumer","test","rebalance","illegal-state"],"backgroundTag":null,"analyzedSha":"996fb4585aa1bcc8980b0e1b8d6b168b986cd979","analyzedAt":"2026-08-11T22:03:28.655Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}