apache/druid · error · IllegalArgumentException

virtualColumn name[ ] not allowed

Error message

virtualColumn name[%s] not allowed

What it means

Virtual column output names must not collide with the special __time column, since __time is always present in segments and shadowing it would be ambiguous. fromIterable throws IAE if any virtual column's output name equals ColumnHolder.TIME_COLUMN_NAME.

Solutions

  1. Rename the virtual column to something like "v_time" and reference that name in the query
  2. Compute time transforms via the __time column with an extraction/expression in selectors instead of shadowing it
  3. Update query-generation code to reject "__time" as a virtual column name

Example fix

// before
new ExpressionVirtualColumn("__time", "timestamp_shift(__time, 'P1D')", ValueType.LONG, macros)
// after
new ExpressionVirtualColumn("v_shifted_time", "timestamp_shift(__time, 'P1D')", ValueType.LONG, macros)
Defensive patterns

Strategy: validation

Validate before calling

if (ColumnHolder.TIME_COLUMN_NAME.equals(vc.getOutputName())) {
  throw new IllegalArgumentException("__time is reserved and cannot be a virtual column name");
}

Try / catch

try {
  VirtualColumns.fromIterable(cols);
} catch (IAE e) {
  log.error(e, "Virtual column name conflicts with __time");
}

Prevention

When it happens

Trigger: Constructing VirtualColumns with a virtual column whose getOutputName() is "__time" — e.g. an expression column intentionally named __time in a native query.

Common situations: Custom queries trying to override __time with a computed timestamp; generated queries colliding names; users unaware __time is reserved.

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/1e91bac6c0038af8. Report an issue: GitHub.

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/segment/VirtualColumns.java:116

    return fromIterable(virtualColumns);
  }

  public static VirtualColumns create(VirtualColumn... virtualColumns)
  {
    return create(Arrays.asList(virtualColumns));
  }

  public static VirtualColumns fromIterable(Iterable<VirtualColumn> virtualColumns)
  {
    Map<String, VirtualColumn> withDotSupport = new HashMap<>();
    Map<String, VirtualColumn> withoutDotSupport = new HashMap<>();
    for (VirtualColumn vc : virtualColumns) {
      if (Strings.isNullOrEmpty(vc.getOutputName())) {
        throw new IAE("Empty or null virtualColumn name");
      }

      if (vc.getOutputName().equals(ColumnHolder.TIME_COLUMN_NAME)) {
        throw new IAE("virtualColumn name[%s] not allowed", vc.getOutputName());
      }

      if (withDotSupport.containsKey(vc.getOutputName()) || withoutDotSupport.containsKey(vc.getOutputName())) {
        throw new IAE("Duplicate virtualColumn name[%s]", vc.getOutputName());
      }

      if (vc.usesDotNotation()) {
        withDotSupport.put(vc.getOutputName(), vc);
      } else {
        withoutDotSupport.put(vc.getOutputName(), vc);
      }
    }
    return new VirtualColumns(ImmutableList.copyOf(virtualColumns), withDotSupport, withoutDotSupport);
  }

  public static VirtualColumns nullToEmpty(@Nullable VirtualColumns virtualColumns)
  {
    return virtualColumns == null ? EMPTY : virtualColumns;

View on GitHub (pinned to 9b90983fd2)