apache/druid · error · IllegalArgumentException
Value of field %s must be a list, found %s
Error message
Value of field %s must be a list, found %s
What it means
A list-typed property in ModelProperties merges an existing list with an updates list (union via sets). This IAE is thrown when either the existing value or the update value is not actually a List — the merge operation requires both operands to be lists.
Source
Thrown at server/src/main/java/org/apache/druid/catalog/model/ModelProperties.java:343
@SuppressWarnings("unchecked")
@Override
public Object merge(Object existing, Object updates)
{
if (updates == null) {
return existing;
}
if (existing == null) {
return updates;
}
List<T> existingList;
List<T> updatesList;
try {
existingList = (List<T>) existing;
updatesList = (List<T>) updates;
}
catch (ClassCastException e) {
throw new IAE(
"Value of field %s must be a list, found %s",
name,
updates.getClass().getSimpleName()
);
}
Set<T> existingSet = new HashSet<>(existingList);
List<T> revised = new ArrayList<>(existingList);
for (T col : updatesList) {
if (!existingSet.contains(col)) {
revised.add(col);
}
}
return revised;
}
}
class StringListPropertyDefn extends ListPropertyDefn<String>
{View on GitHub (pinned to 9b90983fd2)
Solutions
- Wrap the update value in a JSON array: pass [value] instead of value.
- Check the existing stored value; if it is not a list, rewrite the whole property rather than merging.
- If a custom ModelProperty definition declares list merging, verify its decode step actually produces a List.
Example fix
// before
{"properties": {"dimensions": "col1"}}
// after
{"properties": {"dimensions": ["col1"]}} Defensive patterns
Strategy: validation
Validate before calling
Object cur = existingProps.get(name);
Object upd = updates.get(name);
if (!(cur instanceof List) || !(upd instanceof List)) {
throw new IllegalArgumentException(name + " requires list values for merge; wrap scalars in an array");
} Type guard
boolean isListValue(Object v) { return v instanceof List; } Try / catch
try { merged = propDef.merge(name, existing, updates); } catch (IllegalArgumentException e) { log.error("Merge requires lists for %s: %s", name, e.getMessage()); } Prevention
- Always send array values for list-typed properties, even for single elements.
- Never send a map or scalar where the stored property is a list.
- When stored state may be non-list (legacy data), replace the property wholesale instead of merging.
When it happens
Trigger: Calling merge on a list-typed field where the stored value or the submitted update is a scalar, map, or string — e.g. updating a list property (like a dimensions list) with a single string instead of an array.
Common situations: Users submit "dimensions": "col1" instead of ["col1"]; a patch/update API call sends a map where the model stores a list; the stored model state was written by an older version using a different shape.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Cannot merge columns of type[%s] and format[%s] and with [%s
- Value [%s] is not valid for property [%s], expected type [%s
- [%s] column must have type [%s] or no type. Found [%s]
- Value [%s] is not valid for property [%s], expected %s
- The update type must be null or [%s]
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/d7ca55b2a4cc81c6.
Report an issue: GitHub.