{"id":"d65492418c4d1cfe","repo":"apache/kafka","slug":"you-can-only-check-the-position-for-partitions-ass-d65492","errorCode":null,"errorMessage":"You can only check the position for partitions assigned to this consumer.","messagePattern":"You can only check the position for partitions assigned to this consumer\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/consumer/internals/ClassicKafkaConsumer.java","lineNumber":877,"sourceCode":"        try {\n            Collection<TopicPartition> parts = partitions.isEmpty() ? this.subscriptions.assignedPartitions() : partitions;\n            subscriptions.requestOffsetReset(parts, AutoOffsetResetStrategy.LATEST);\n        } finally {\n            release();\n        }\n    }\n\n    @Override\n    public long position(TopicPartition partition) {\n        return position(partition, Duration.ofMillis(defaultApiTimeoutMs));\n    }\n\n    @Override\n    public long position(TopicPartition partition, final Duration timeout) {\n        acquireAndEnsureOpen();\n        try {\n            if (!this.subscriptions.isAssigned(partition))\n                throw new IllegalStateException(\"You can only check the position for partitions assigned to this consumer.\");\n\n            Timer timer = time.timer(timeout);\n            do {\n                SubscriptionState.FetchPosition position = this.subscriptions.validPosition(partition);\n                if (position != null)\n                    return position.offset;\n\n                updateFetchPositions(timer);\n                client.poll(timer);\n            } while (timer.notExpired());\n\n            throw new TimeoutException(\"Timeout of \" + timeout.toMillis() + \"ms expired before the position \" +\n                    \"for partition \" + partition + \" could be determined\");\n        } finally {\n            release();\n        }\n    }\n","sourceCodeStart":859,"sourceCodeEnd":895,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/consumer/internals/ClassicKafkaConsumer.java#L859-L895","documentation":"Thrown by KafkaConsumer.position(TopicPartition, Duration) when the requested partition is not in the consumer's current assignment (subscriptions.isAssigned returns false). The consumer cannot report a fetch position for a partition it is not consuming, so this IllegalStateException signals a logic error in the caller. It occurs before any network call.","triggerScenarios":"Calling position(tp) for a TopicPartition obtained from partitionsFor() or listTopics() instead of from assignment(); calling position on a partition whose assignment was revoked after a rebalance; mixing manual assignment and subscription and querying the wrong set.","commonSituations":"Calling position() immediately after subscribe() before poll() has triggered assignment; reading partition list from topic metadata instead of consumer.assignment(); bug exposed after rebalances that shrink the assignment; threads sharing a partition set without syncing with assignment updates.","solutions":["Only call position() for partitions returned by consumer.assignment(); verify membership first.","Ensure at least one poll() has completed so assignment is populated before querying position.","Handle ConsumerRebalanceListener to refresh your cached partition set, then guard position() calls against the live assignment."],"exampleFix":"// before\nlong pos = consumer.position(new TopicPartition(\"orders\", 0));\n\n// after\nTopicPartition tp = new TopicPartition(\"orders\", 0);\nif (consumer.assignment().contains(tp)) {\n    long pos = consumer.position(tp);\n}","handlingStrategy":"validation","validationCode":"// Only query position() for partitions currently in the assignment:\nSet<TopicPartition> assigned = consumer.assignment();\nif (assigned.contains(tp)) {\n    return consumer.position(tp);\n}\nthrow new IllegalStateException(\"Partition \" + tp + \" is not assigned; current: \" + assigned);","typeGuard":"// Narrow a TopicPartition to the 'assigned' subset before use:\nstatic Optional<TopicPartition> ifAssigned(Consumer<?,?> c, TopicPartition tp) {\n    return c.assignment().contains(tp) ? Optional.of(tp) : Optional.empty();\n}\n// Usage: ifAssigned(consumer, tp).ifPresent(consumer::position);","tryCatchPattern":"// Recovery: drop the unassigned partition and continue, since position() is undefined for it:\ntry {\n    pos = consumer.position(tp);\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"assigned to this consumer\")) {\n        log.warn(\"Skipping unassigned {}\", tp);\n        continue;\n    }\n    throw e;\n}","preventionTips":["Treat consumer.assignment() as the single source of truth inside a ConsumerRebalanceListener.onAssign/onRevoke boundary; never cache partition sets across rebalances.","Re-derive the partition list right before calling position()/seek()/pause() rather than reusing one captured earlier.","In manual-assignment mode, confirm partition.exists(partition) and the assign() call succeeded before any positional query."],"tags":["consumer","assignment","api-misuse","java"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}