{"record":{"id":"cccc0b0f039b2e36","repo":"apache/pulsar","slug":"must-have-at-least-1-segment","errorCode":null,"errorMessage":"Must have at least 1 segment","messagePattern":"Must have at least 1 segment","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/service/scalable/ScalableTopicController.java","lineNumber":1555,"sourceCode":"     */\n    public static ScalableTopicMetadata createInitialMetadata(int numInitialSegments,\n                                                        int entryBucketBudget,\n                                                        Map<String, String> properties) {\n        return createInitialMetadata(numInitialSegments, entryBucketBudget,\n                EntryBucketSplits.MAX_BUCKETS, properties);\n    }\n\n    /**\n     * As {@link #createInitialMetadata(int, int, Map)}, clamping each initial segment's\n     * budget-derived entry-bucket count to {@code maxBucketsPerSegment} (the configured\n     * per-segment ceiling — the budget is a dynamic setting and must not exceed it).\n     */\n    public static ScalableTopicMetadata createInitialMetadata(int numInitialSegments,\n                                                        int entryBucketBudget,\n                                                        int maxBucketsPerSegment,\n                                                        Map<String, String> properties) {\n        if (numInitialSegments < 1) {\n            throw new IllegalArgumentException(\"Must have at least 1 segment\");\n        }\n\n        int rangeSize = (HashRange.MAX_HASH + 1) / numInitialSegments;\n        Map<Long, SegmentInfo> segments = new LinkedHashMap<>();\n\n        // PIP-486: share the topic's entry-bucket budget equally across the initial segments.\n        List<Integer> entryBucketSplits = EntryBucketSplits.equalWidth(\n                Math.min(EntryBucketSplits.bucketsForBudget(entryBucketBudget, numInitialSegments),\n                        maxBucketsPerSegment));\n\n        long nowMs = System.currentTimeMillis();\n        for (int i = 0; i < numInitialSegments; i++) {\n            int start = i * rangeSize;\n            int end = (i == numInitialSegments - 1) ? HashRange.MAX_HASH : (start + rangeSize - 1);\n            HashRange range = HashRange.of(start, end);\n            SegmentInfo segment = SegmentInfo.active(i, range, 0, nowMs)\n                    .withEntryBucketSplits(entryBucketSplits);\n            segments.put((long) i, segment);","sourceCodeStart":1537,"sourceCodeEnd":1573,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/scalable/ScalableTopicController.java#L1537-L1573","documentation":"ScalableTopicController.createInitialMetadata builds the bootstrap SegmentLayout metadata for a new scalable topic, dividing the full hash range into numInitialSegments equal ranges. Fewer than 1 segment is nonsensical (division by zero / empty layout), so an IllegalArgumentException is thrown.","triggerScenarios":"Calling createInitialMetadata with numInitialSegments < 1 (0, negative) when creating initial topic metadata.","commonSituations":"Config value for initial segments read from properties with a typo or unset so it defaults to 0; computation like totalRanges/hashRangeSize rounding to 0.","solutions":["Ensure numInitialSegments >= 1 before calling createInitialMetadata","Fix the source config/property feeding numInitialSegments and give it a sane default (e.g. 1 or 4)","Add a caller-side guard or clamp: Math.max(1, configuredValue)"],"exampleFix":"// before\nint numInitialSegments = Integer.parseInt(props.getProperty(\"initialSegments\")); // null -> 0\n// after\nint numInitialSegments = Math.max(1, Integer.parseInt(props.getProperty(\"initialSegments\", \"1\")));","handlingStrategy":"validation","validationCode":"int n = configuredInitialSegments();\nif (n < 1) throw new IllegalArgumentException(\"numInitialSegments must be >= 1, got \" + n);\nScalableTopicController.createInitialMetadata(n, budget, maxBuckets, props);","typeGuard":null,"tryCatchPattern":"try {\n    metadata = ScalableTopicController.createInitialMetadata(n, budget, maxBuckets, props);\n} catch (IllegalArgumentException e) {\n    log.error(\"Bad initial segment count: {}\", e.getMessage());\n}","preventionTips":["Default numInitialSegments to >= 1 when reading from properties","Clamp with Math.max(1, value) at config parse time","Unit-test metadata creation with boundary values 0 and 1"],"tags":["pulsar","scalable-topic","illegal-argument","metadata"],"backgroundTag":"invalid-configuration-value","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}