{"record":{"id":"f4266015f1d57161","repo":"apache/druid","slug":"bucketsize-must-be-a-power-of-two-from-1-up-to-12","errorCode":null,"errorMessage":"bucketSize must be a power of two (from 1 up to 128) but was[%,d]","messagePattern":"bucketSize must be a power of two \\(from 1 up to 128\\) but was\\[%,d\\]","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/segment/data/FrontCodedIndexedWriter.java","lineNumber":86,"sourceCode":"  private WriteOutBytes headerOut = null;\n  @Nullable\n  private WriteOutBytes valuesOut = null;\n  private int numWritten = 0;\n  private ByteBuffer scratch;\n  private int logScratchSize = 10;\n  private boolean isClosed = false;\n  private boolean hasNulls = false;\n\n\n  public FrontCodedIndexedWriter(\n      SegmentWriteOutMedium segmentWriteOutMedium,\n      ByteOrder byteOrder,\n      int bucketSize,\n      byte version\n  )\n  {\n    if (Integer.bitCount(bucketSize) != 1 || bucketSize < 1 || bucketSize > 128) {\n      throw new IAE(\"bucketSize must be a power of two (from 1 up to 128) but was[%,d]\", bucketSize);\n    }\n    this.segmentWriteOutMedium = segmentWriteOutMedium;\n    this.scratch = ByteBuffer.allocate(1 << logScratchSize).order(byteOrder);\n    this.bucketSize = bucketSize;\n    this.byteOrder = byteOrder;\n    this.bucketBuffer = new byte[bucketSize][];\n    this.getOffsetBuffer = ByteBuffer.allocate(Integer.BYTES).order(byteOrder);\n    this.div = Integer.numberOfTrailingZeros(bucketSize);\n    this.version = FrontCodedIndexed.validateVersion(version);\n  }\n\n  @Override\n  public void open() throws IOException\n  {\n    headerOut = segmentWriteOutMedium.makeWriteOutBytes();\n    valuesOut = segmentWriteOutMedium.makeWriteOutBytes();\n  }\n","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/segment/data/FrontCodedIndexedWriter.java#L68-L104","documentation":"FrontCodedIndexedWriter's constructor validates that bucketSize is a power of two between 1 and 128 inclusive. Power-of-two bucket sizes are required for the bit-shift based indexing, and the 1..128 cap bounds memory (bucketBuffer and scratch sizing). Invalid values throw IAE before any writing happens.","triggerScenarios":"Constructing FrontCodedIndexedWriter with bucketSize values like 0, 3, 5, 6, or 256 — i.e. any value failing Integer.bitCount(bucketSize) == 1 || bucketSize < 1 || bucketSize > 128. This typically comes from a user-supplied frontCoded bucketSize config (e.g. SQL dictionary compression config) that was not validated.","commonSituations":"Setting the front-coded dictionary compression bucket size in ingestion/SQL configs to a non-power-of-two like 5 or 10; copy-paste of an example bucketSize; assuming any positive size is allowed.","solutions":["Set bucketSize to a power of two between 1 and 128 (the default is 4)","Validate user config before passing it to the writer: (bucketSize & (bucketSize - 1)) == 0 && bucketSize >= 1 && bucketSize <= 128","Use FrontCodedIndexed.write() helpers or config parsing that clamps/validates the bucket size automatically","If coming from SQL/ingestion spec, correct the 'compressionFormat': 'frontCoded' with a legal bucketSize parameter"],"exampleFix":"// before\nint bucketSize = 5;\nnew FrontCodedIndexedWriter<>(medium, ordering, byteOrder, bucketSize, version); // IAE\n// after\nint bucketSize = 8; // power of two, 1..128\nnew FrontCodedIndexedWriter<>(medium, ordering, byteOrder, bucketSize, version);","handlingStrategy":"validation","validationCode":"boolean validBucketSize(int n) {\n  return n >= 1 && n <= 128 && Integer.bitCount(n) == 1;\n}\n// call before constructing: if (!validBucketSize(bucketSize)) fail fast","typeGuard":null,"tryCatchPattern":"try {\n  writer = new FrontCodedIndexedWriter<>(medium, ordering, byteOrder, bucketSize, version);\n} catch (IllegalArgumentException e) {\n  // fall back to DEFAULT_BUCKET_SIZE (4) or reject the config\n}","preventionTips":["Validate user-supplied bucketSize configs at config-parse time","Stick to powers of two: 1, 2, 4, 8, ..., 128; default 4 is safe","Clamp or reject non-power-of-two values before they reach the writer","Document the 1..128 power-of-two constraint wherever bucketSize is exposed"],"tags":["validation","serialization","config"],"backgroundTag":"invalid-argument-value","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}