apache/druid · error · DruidException
Cannot coerce value [ ] of type [ ] for column [ ] to
Error message
Cannot coerce value [%s] of type [%s] for column [%s] to %s
What it means
ClusterGroupTuples.coerceValue canonicalizes clustering-column tuple values to their declared ColumnType so equality works across the JSON/programmatic boundary. For LONG columns it only accepts Number instances and calls longValue(); anything else (String, Boolean, etc.) triggers InvalidInput 'Cannot coerce value ... to LONG'. Strings are deliberately not parsed to avoid silently accepting operator typos.
Solutions
- Change the tuple value to a JSON number for LONG columns: use 42 not "42"
- Fix the rule/JSON authoring tool to emit typed numbers instead of strings
- If values truly are numeric strings, parse them at authoring time (e.g. Long.parseLong) before constructing ClusterGroupTuples; the library intentionally will not parse them
Example fix
// before (rule JSON)
{"tuples": [["1000"]]}
// after
{"tuples": [[1000]]} Defensive patterns
Strategy: validation
Validate before calling
Object v = tuple.get(i);
if (v != null && "LONG".equals(declaredType) && !(v instanceof Number)) {
throw new IllegalArgumentException(
"Column " + name + " expects a JSON number (LONG), got: " + v.getClass().getSimpleName());
} Type guard
boolean isTypedNumber(Object v) {
return v instanceof Number;
} Try / catch
try {
ClusterGroupTuples ct = new ClusterGroupTuples(signature, virtualColumns, tuples);
} catch (InvalidInput e) {
if (e.getMessage() != null && e.getMessage().contains("Cannot coerce value")) {
log.error("Rule tuple has wrong JSON type (quoted number?); fix to numeric literal");
return null; // treat as no-match per documented rule-matcher guidance
}
throw e;
} Prevention
- Author rule JSON with unquoted numeric literals for LONG/DOUBLE/FLOAT columns
- Validate rule files against the segment RowSignature before submitting
- Never stringify numbers when serializing cluster-group tuples; keep Jackson's numeric typing intact
When it happens
Trigger: Constructing ClusterGroupTuples (via constructor or Jackson deserialization) whose tuple value for a LONG clustering column is a non-Number, e.g. a JSON string "42" or boolean where a numeric JSON value 42 is required; canonicalizeTuples calls coerceValue and throws.
Common situations: Hand-authored partial-load rule JSON with quoted numbers ("42" instead of 42); rule files produced by tools that stringify values; clustering columns declared LONG in the segment signature but rule tuples authored as strings.
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 specify DESC clustering key
- Expected key [ ] to be CSV or JSON array, but got [ ]
- Failed to deserialize authorizer role, ignoring
- Failed to parse metric dimensions and types
- must have an even number of arguments
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/b8eaab78a55e8594.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/timeline/ClusterGroupTuples.java:107
* <li>{@link ClusterGroupTuples}'s compact constructor to canonicalize segment-side tuples (strict).</li>
* <li>Operator-supplied rule tuples in future cluster-group partial-load matchers, which can catch the
* exception and treat it as "no match for this segment" rather than a hard failure.</li>
* </ul>
*/
@Nullable
public static Object coerceValue(String columnName, ColumnType type, @Nullable Object raw)
{
if (raw == null) {
return null;
}
if (ColumnType.STRING.equals(type)) {
return raw instanceof String ? raw : Objects.toString(raw);
}
if (ColumnType.LONG.equals(type)) {
if (raw instanceof Number) {
return ((Number) raw).longValue();
}
throw cannotCoerce(raw, columnName, "LONG");
}
if (ColumnType.DOUBLE.equals(type)) {
if (raw instanceof Number) {
return ((Number) raw).doubleValue();
}
throw cannotCoerce(raw, columnName, "DOUBLE");
}
if (ColumnType.FLOAT.equals(type)) {
if (raw instanceof Number) {
return ((Number) raw).floatValue();
}
throw cannotCoerce(raw, columnName, "FLOAT");
}
throw InvalidInput.exception(
"Unsupported clustering column type [%s] for column [%s]; supported types are STRING, LONG, DOUBLE, FLOAT",
type,
columnName
);View on GitHub (pinned to 9b90983fd2)