apache/druid · error · IllegalArgumentException

Column[%s] does not start with prefix[%s]

Error message

Column[%s] does not start with prefix[%s]

What it means

JoinPrefixUtils.unprefix strips a join-table prefix (e.g. 'l1.') from a column name, but only if the column actually starts with that prefix. If it does not, Druid throws this IllegalArgumentException because returning the original name would silently mis-map columns in a join.

Source

Thrown at processing/src/main/java/org/apache/druid/segment/join/JoinPrefixUtils.java:72

  }

  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.,
   * if {@link #isPrefixedBy(String, String)} would return true on the same arguments.
   *
   * @throws IllegalArgumentException if columnName does not start with prefix
   */
  public static String unprefix(final String columnName, final String prefix)
  {
    if (isPrefixedBy(columnName, prefix)) {
      return columnName.substring(prefix.length());
    } else {
      throw new IAE("Column[%s] does not start with prefix[%s]", columnName, prefix);
    }
  }

  /**
   * Check if any prefixes in the provided list duplicate or shadow each other.
   *
   * @param prefixes A mutable list containing the prefixes to check. This list will be sorted by descending
   *                 string length.
   */
  public static void checkPrefixesForDuplicatesAndShadowing(
      final List<String> prefixes
  )
  {
    // this is a naive approach that assumes we'll typically handle only a small number of prefixes
    prefixes.sort(DESCENDING_LENGTH_STRING_COMPARATOR);
    for (int i = 0; i < prefixes.size(); i++) {
      String prefix = prefixes.get(i);
      for (int k = i + 1; k < prefixes.size(); k++) {

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Check the join clause and the prefix declared on the joinable dataSource match the column name being unprefixed
  2. Remove or correct the prefix parameter so it equals the actual prefix of the column name
  3. Ensure all right-side columns in equi conditions are prefixed consistently when building the native query

Example fix

// before
String name = JoinPrefixUtils.unprefix("country_code", "l1."); // IAE
// after
String name = JoinPrefixUtils.unprefix("l1.country_code", "l1.");
Defensive patterns

Strategy: validation

Validate before calling

if (!columnName.startsWith(prefix)) { throw new IllegalArgumentException("Column " + columnName + " lacks prefix " + prefix); }
String bare = JoinPrefixUtils.unprefix(columnName, prefix);

Type guard

boolean isPrefixed(String col, String prefix) { return col != null && prefix != null && col.startsWith(prefix); }

Try / catch

try { return JoinPrefixUtils.unprefix(columnName, prefix); } catch (IllegalArgumentException e) { log.error("prefix mismatch: {} vs {}", columnName, prefix); throw e; }

Prevention

When it happens

Trigger: Calling JoinPrefixUtils.unprefix(columnName, prefix) where columnName does not begin with prefix; typically reached when join column names in a join clause were computed with a different prefix than the one used during unprefixing.

Common situations: Misconfigured join condition column names in a native join (prefix mismatch between the join clause and the table prefix), SQL plan translation bugs where right-column identifiers were not prefixed, or user-supplied native JSON joins where the equated column name lacks the declared prefix.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/b9fe0602dbbe6cc4. Report an issue: GitHub.