{"record":{"id":"0d571552355a0fea","repo":"apache/druid","slug":"maxstringbytes-must-be-greater-than-0-0d5715","errorCode":null,"errorMessage":"maxStringBytes must be greater than 0","messagePattern":"maxStringBytes must be greater than 0","errorType":"validation","errorClass":"org.apache.druid.java.util.common.IAE","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/query/aggregation/firstlast/first/StringFirstAggregatorFactory.java","lineNumber":146,"sourceCode":"\n  private final String fieldName;\n  private final String name;\n  private final String timeColumn;\n  protected final int maxStringBytes;\n\n  @JsonCreator\n  public StringFirstAggregatorFactory(\n      @JsonProperty(\"name\") String name,\n      @JsonProperty(\"fieldName\") final String fieldName,\n      @JsonProperty(\"timeColumn\") @Nullable final String timeColumn,\n      @JsonProperty(\"maxStringBytes\") Integer maxStringBytes\n  )\n  {\n    Preconditions.checkNotNull(name, \"Must have a valid, non-null aggregator name\");\n    Preconditions.checkNotNull(fieldName, \"Must have a valid, non-null fieldName\");\n\n    if (maxStringBytes != null && maxStringBytes < 0) {\n      throw new IAE(\"maxStringBytes must be greater than 0\");\n    }\n\n    this.name = name;\n    this.fieldName = fieldName;\n    this.timeColumn = timeColumn == null ? ColumnHolder.TIME_COLUMN_NAME : timeColumn;\n    this.maxStringBytes = maxStringBytes == null\n                          ? StringFirstAggregatorFactory.DEFAULT_MAX_STRING_SIZE\n                          : maxStringBytes;\n  }\n\n\n  @Override\n  public Aggregator factorize(ColumnSelectorFactory metricFactory)\n  {\n    final BaseObjectColumnValueSelector<?> valueSelector = metricFactory.makeColumnValueSelector(fieldName);\n    if (valueSelector instanceof NilColumnValueSelector) {\n      return NIL_AGGREGATOR;\n    } else {","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/aggregation/firstlast/first/StringFirstAggregatorFactory.java#L128-L164","documentation":"StringFirstAggregatorFactory validates maxStringBytes in its constructor: a non-null negative value is rejected with this IllegalArgumentException (via Preconditions/IAE). The message is slightly misleading — the check actually rejects negative values; only non-negative values pass. It protects the aggregator's string-chopping logic from nonsense bounds.","triggerScenarios":"Constructing StringFirstAggregatorFactory (directly in Java or via JSON deserialization of a native query spec) with maxStringBytes set to a negative number.","commonSituations":"Hand-written query JSON with maxStringBytes: -1 intending 'unlimited'; config generated programmatically with a sentinel -1; copy-paste from code that used -1 as a default elsewhere.","solutions":["Set maxStringBytes to a positive integer (or omit/null it to use the default 1023).","If the intent was unlimited, remove the field rather than passing a negative sentinel.","Fix the producing code/config generator so it emits null or a positive value instead of -1.","Re-validate the query spec JSON before submission."],"exampleFix":"// before\n{\"type\":\"stringFirst\",\"name\":\"s\",\"fieldName\":\"col\",\"maxStringBytes\":-1}\n// after\n{\"type\":\"stringFirst\",\"name\":\"s\",\"fieldName\":\"col\"}","handlingStrategy":"validation","validationCode":"if (maxStringBytes != null && maxStringBytes < 0) {\n  throw new IllegalArgumentException(\"maxStringBytes must be >= 0\");\n}\nnew StringFirstAggregatorFactory(name, field, null, maxStringBytes);","typeGuard":null,"tryCatchPattern":"try {\n  factory = mapper.readValue(spec, StringFirstAggregatorFactory.class);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"maxStringBytes\")) {\n    throw new QuerySpecValidationException(\"maxStringBytes must be a non-negative integer\");\n  }\n  throw e;\n}","preventionTips":["Never use -1 as an 'unlimited' sentinel for maxStringBytes.","Omit the field to use the default (1023).","Validate query JSON with the schema before submission."],"tags":["druid","aggregation","configuration"],"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"}