apache/druid · error · IllegalArgumentException
Join clause cannot have null or empty prefix
Error message
Join clause cannot have null or empty prefix
What it means
JoinPrefixUtils.validatePrefix checks that a join clause prefix is usable: a null or empty prefix cannot namespace the joinable's columns, so it throws this IAE. Prefixes exist to qualify joined column names and prevent collisions.
Solutions
- Set a non-empty prefix on the JoinableClause (or use the joinable's name via the prefix field in the native join)
- In native JSON joins, populate "prefix" (e.g. "j0.", "j1.") for right-side joinables
- If generating queries programmatically, default the prefix to a unique identifier per clause
Example fix
// before
{"rightSubQuery": ..., "prefix": null, ...}
// after
{"rightSubQuery": ..., "prefix": "j0.", ...} Defensive patterns
Strategy: validation
Validate before calling
if (prefix == null || prefix.isEmpty()) throw new IllegalArgumentException("Join prefix required"); Try / catch
try { JoinPrefixUtils.validatePrefix(prefix); } catch (IAE e) { if (e.getMessage().contains("null or empty")) { /* set prefix */ } throw e; } Prevention
- Always populate prefix in native join queries
- Default programmatic prefixes to j0., j1., ...
When it happens
Trigger: Creating a JoinableClause or validating a join in the query planner with prefix null or "", e.g. building joins from parsed SQL/subquery references without an explicit prefix.
Common situations: Programmatic native query construction omitting the prefix field; planner bugs where subquery join prefixes are not assigned; hand-written native JSON with "prefix": "".
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- BroadcastTablesTooLarge
- Caching is not supported. Check `isCacheable` before…
- Cannot build hash-join matcher on non-equi-join condition
- Cannot build hash-join matcher on non-key-based condition
- Cannot handle constant condition
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/7ef81ba0f73a4154.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/segment/join/JoinPrefixUtils.java:44
import java.util.Comparator;
import java.util.List;
/**
* Utility class for working with prefixes in join operations
*/
public class JoinPrefixUtils
{
private static final Comparator<String> DESCENDING_LENGTH_STRING_COMPARATOR = (s1, s2) ->
Integer.compare(s2.length(), s1.length());
/**
* Checks that "prefix" is a valid prefix for a join clause (see {@link JoinableClause#getPrefix()}) and, if so,
* returns it. Otherwise, throws an exception.
*/
public static String validatePrefix(@Nullable final String prefix)
{
if (prefix == null || prefix.isEmpty()) {
throw new IAE("Join clause cannot have null or empty prefix");
} else if (isPrefixedBy(ColumnHolder.TIME_COLUMN_NAME, prefix) || ColumnHolder.TIME_COLUMN_NAME.equals(prefix)) {
throw new IAE(
"Join clause cannot have prefix[%s], since it would shadow %s",
prefix,
ColumnHolder.TIME_COLUMN_NAME
);
} else {
return prefix;
}
}
public static boolean isPrefixedBy(final String columnName, final String prefix)
{
return columnName.length() > prefix.length() && columnName.startsWith(prefix);
}
/**
* Removes the prefix on {@code columnName}. Must only be called if the column name is actually prefixed; i.e.,View on GitHub (pinned to 9b90983fd2)