apache/beam · error · IllegalArgumentException

Unsupported precision for Timestamp logical type

Error message

Unsupported precision for Timestamp logical type 

What it means

toTableFieldSchema throws this IllegalArgumentException when converting a Beam Schema field whose logical type is the Timestamp logical type but whose precision argument is not 9 (nanoseconds). The converter only supports mapping Beam Timestamp logical types with nanosecond precision to a BigQuery TIMESTAMP column with 12-digit (pico) precision; any other precision (millis, micros, etc.) is rejected.

Source

Thrown at sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryUtils.java:591

        field.setFields(toTableFieldSchema(subType));
      }
      if (TypeName.MAP == type.getTypeName()) {
        FieldType mapKeyType = Preconditions.checkArgumentNotNull(type.getMapKeyType());
        FieldType mapValueType = Preconditions.checkArgumentNotNull(type.getMapValueType());
        Schema mapSchema =
            Schema.builder()
                .addField(BIGQUERY_MAP_KEY_FIELD_NAME, mapKeyType)
                .addField(BIGQUERY_MAP_VALUE_FIELD_NAME, mapValueType)
                .build();
        type = FieldType.row(mapSchema);
        field.setFields(toTableFieldSchema(mapSchema));
        field.setMode(Mode.REPEATED.toString());
      }
      Schema.LogicalType<?, ?> logicalType = type.getLogicalType();
      if (logicalType != null && Timestamp.IDENTIFIER.equals(logicalType.getIdentifier())) {
        int precision = Preconditions.checkArgumentNotNull(logicalType.getArgument());
        if (precision != 9) {
          throw new IllegalArgumentException(
              "Unsupported precision for Timestamp logical type " + precision);
        }
        field.setType(StandardSQLTypeName.TIMESTAMP.toString()).setTimestampPrecision(12L);
      } else {
        field.setType(toStandardSQLTypeName(type).toString());
      }

      fields.add(field);
    }
    return fields;
  }

  /** Convert a Beam {@link Schema} to a BigQuery {@link TableSchema}. */
  public static TableSchema toTableSchema(Schema schema) {
    return new TableSchema().setFields(toTableFieldSchema(schema));
  }

  /** Convert a BigQuery {@link TableSchema} to a Beam {@link Schema}. */

View on GitHub (pinned to 12126d8942)

Solutions

  1. Use the nanosecond Timestamp logical type: FieldType.logicalType(Timestamp.NANOS) for the affected field before writing to BigQuery.
  2. Alternatively change the field to FieldType.DATETIME (micros) which maps to a plain BigQuery TIMESTAMP without the precision path.
  3. Transform the schema/rows with Schema.toBuilder()/Row conversions to convert logical type precision (e.g. beam convertTimestamps) prior to the sink.

Example fix

// before
Field f = Field.of("ts", FieldType.logicalType(Timestamp.MICROS));
// after
Field f = Field.of("ts", FieldType.logicalType(Timestamp.NANOS));
Defensive patterns

Strategy: validation

Validate before calling

static void assertTimestampPrecisionsAreNanos(Schema schema) {
  for (Field f : schema.getFields()) {
    Schema.LogicalType<?, ?> lt = f.getType().getLogicalType();
    if (lt != null && "Timestamp".equals(lt.getIdentifier())) {
      Object arg = lt.getArgument();
      if (arg instanceof Number && ((Number) arg).intValue() != 9) {
        throw new IllegalArgumentException("Field " + f.getName() + " needs Timestamp.NANOS (precision 9) for BigQuery");
      }
    }
  }
}

Type guard

static boolean isBqCompatibleTimestamp(Field f) {
  Schema.LogicalType<?, ?> lt = f.getType().getLogicalType();
  return lt == null || !"Timestamp".equals(lt.getIdentifier())
      || (lt.getArgument() instanceof Number && ((Number) lt.getArgument()).intValue() == 9);
}

Try / catch

try {
  TableSchema ts = BigQueryUtils.toTableSchema(beamSchema);
} catch (IllegalArgumentException e) {
  if (String.valueOf(e.getMessage()).startsWith("Unsupported precision for Timestamp")) {
    Schema fixed = rebuildWithNanosTimestamps(beamSchema);
    TableSchema ts = BigQueryUtils.toTableSchema(fixed);
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling BigQueryUtils.toTableSchema / BigQueryIO.writeTableRows-ish schema writes with a Beam Schema field typed FieldType.logicalType(Timestamp.MILLIS) (argument 3), Timestamp.MICROS (6), or any Timestamp logical type whose getArgument() is not 9.

Common situations: Schemas built with Timestamp.MICROS/MILLIS for readability, then written to BigQuery where only nanosecond-precision Timestamp logical types are accepted by this converter; sharing a schema across sinks (Parquet accepts micros, BigQuery does not).

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/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/0f5a3e64e2ddb3f7. Report an issue: GitHub.