apache/druid · error · MSQException

Unknown

Unknown

Error message

Incorrect type for column [%s]. Expected LONG but got type [%s]. Please ensure that the value is cast to LONG.

What it means

MSQTasks.primaryTimestampFromObjectForInsert requires the __time primary timestamp value for an INSERT to be a Long (epoch millis). If the supplied object is any other type, an MSQException is thrown instructing the user to cast the value to LONG.

Source

Thrown at multi-stage-query/src/main/java/org/apache/druid/msq/exec/MSQTasks.java:125

  public static long primaryTimestampFromObjectForInsert(final Object timestamp)
  {
    if (timestamp instanceof Long) {
      return (long) timestamp;
    } else if (timestamp == null) {
      throw new MSQException(InsertTimeNullFault.INSTANCE);
    } else {
      // Normally we expect the SQL layer to validate that __time for INSERT is a TIMESTAMP type, which would
      // be a long at execution time. So a nice user-friendly message isn't needed here: it would only happen
      // if the SQL layer is bypassed. Nice, friendly users wouldn't do that :)
      final UnknownFault fault =
          UnknownFault.forMessage(
              StringUtils.format(
                  "Incorrect type for column [%s]. Expected LONG but got type [%s]. Please ensure that the value is cast to LONG.",
                  ColumnHolder.TIME_COLUMN_NAME,
                  timestamp.getClass().getSimpleName()
              )
          );
      throw new MSQException(fault);
    }
  }

  /**
   * Returns the host:port from a {@link DruidNode}. Convenience method to make it easier to construct
   * {@link MSQErrorReport} instances.
   */
  @Nullable
  static String getHostFromSelfNode(@Nullable final DruidNode selfNode)
  {
    return selfNode != null ? selfNode.getHostAndPortToUse() : null;
  }

  static StorageConnector makeStorageConnector(final Injector injector)
  {
    try {
      StorageConnector storageConnector = injector.getInstance(Key.get(StorageConnector.class, MultiStageQuery.class));
      if (storageConnector instanceof NilStorageConnector) {

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. CAST the expression to BIGINT before assigning it to __time, e.g. CAST(TIME_PARSE(ts) AS BIGINT) or UNIX_TIMESTAMP(ts)
  2. Use functions that return epoch millis (MILLIS_TO_TIMESTAMP inverse: TIME_TO_MILLIS)
  3. Inspect the query's projected type for __time and ensure the final expression is BIGINT

Example fix

// before
INSERT INTO dst SELECT '2024-01-01T00:00:00' AS __time ... FROM src
// after
INSERT INTO dst SELECT TIME_TO_MILLIS(TIME_PARSE('2024-01-01T00:00:00')) AS __time ... FROM src
Defensive patterns

Strategy: type-guard

Validate before calling

Object v = expr.eval(row);
if (!(v instanceof Long)) { throw new IllegalArgumentException("__time must be BIGINT/LONG, got " + (v == null ? "null" : v.getClass().getSimpleName())); }

Type guard

boolean isLongTimestamp(Object v) { return v instanceof Long; }

Try / catch

try { client.sqlQuery(insert); } catch (MSQException e) { if (e.getMessage().contains("Expected LONG")) { rewriteQueryWithCast(); } else { throw e; } }

Prevention

When it happens

Trigger: MSQ INSERT where the value provided for column __time evaluates to a non-LONG type (e.g. STRING timestamp, TIMESTAMP object, DOUBLE) instead of a Java Long.

Common situations: Writing a string date like '2023-01-01' directly to __time without CAST; a query returning __time as VARCHAR due to upstream casting; passing TIMESTAMP-typed expressions that MSQ doesn't auto-convert.

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


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