apache/beam · error · RuntimeException

Unhandled logical type ${identifier}

Error message

Unhandled logical type ${identifier}

What it means

During Beam FieldType -> Avro schema conversion, the FieldType carries a logical type whose identifier is not handled by the converter (only Timestamp-related identifiers are supported in that switch). The library throws RuntimeException because it cannot map the logical type to any Avro representation.

Source

Thrown at sdks/java/extensions/avro/src/main/java/org/apache/beam/sdk/extensions/avro/schemas/utils/AvroUtils.java:1235

                  .addToSchema(org.apache.avro.Schema.create(org.apache.avro.Schema.Type.INT));
        } else if ("TIME".equals(identifier)) {
          baseType =
              LogicalTypes.timeMillis()
                  .addToSchema(org.apache.avro.Schema.create(org.apache.avro.Schema.Type.INT));
        } else if (SqlTypes.TIMESTAMP.getIdentifier().equals(identifier)) {
          baseType =
              LogicalTypes.timestampMicros()
                  .addToSchema(org.apache.avro.Schema.create(org.apache.avro.Schema.Type.LONG));
        } else if (Timestamp.IDENTIFIER.equals(identifier)) {
          int precision = checkNotNull(logicalType.getArgument());
          if (precision != 9) {
            throw new RuntimeException(
                "Timestamp logical type precision not supported:" + precision);
          }
          baseType = org.apache.avro.Schema.create(org.apache.avro.Schema.Type.LONG);
          baseType.addProp("logicalType", TIMESTAMP_NANOS_LOGICAL_TYPE);
        } else {
          throw new RuntimeException(
              "Unhandled logical type " + checkNotNull(fieldType.getLogicalType()).getIdentifier());
        }
        break;

      case ARRAY:
      case ITERABLE:
        baseType =
            org.apache.avro.Schema.createArray(
                getFieldSchema(
                    checkNotNull(fieldType.getCollectionElementType()), fieldName, namespace));
        break;

      case MAP:
        if (checkNotNull(fieldType.getMapKeyType()).getTypeName().isStringType()) {
          // Avro only supports string keys in maps.
          baseType =
              org.apache.avro.Schema.createMap(
                  getFieldSchema(checkNotNull(fieldType.getMapValueType()), fieldName, namespace));

View on GitHub (pinned to 12126d8942)

Solutions

  1. Remove or replace the unsupported logical type on the FieldType before conversion.
  2. Implement a mapping yourself by converting the field to its base type and attaching the Avro logical-type prop manually.
  3. Register/extend the converter (or upstream a case for the identifier) if the logical type is broadly useful.
  4. Catch RuntimeException around schema conversion and fall back to the field's underlying primitive type.

Example fix

// before
Field.of("status", FieldType.string().withLogicalType(new MyCustomLogicalType()))
// after
Field.of("status", FieldType.string()) // drop unsupported logical type before toAvroSchema
Defensive patterns

Strategy: validation

Validate before calling

boolean hasSupportedLogicalType(FieldType ft) {
  LogicalType lt = ft.getLogicalType();
  return lt == null || SUPPORTED_IDENTIFIERS.contains(lt.getIdentifier()); // e.g. Timestamp variants only
}

Try / catch

try {
  org.apache.avro.Schema s = AvroUtils.toAvroSchema(rowSchema);
} catch (RuntimeException e) {
  if (e.getMessage() != null && e.getMessage().startsWith("Unhandled logical type ")) {
    org.apache.avro.Schema s2 = AvroUtils.toAvroSchema(stripLogicalTypes(rowSchema));
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling AvroUtils.getFieldSchema/toAvroSchema with a FieldType whose getLogicalType() has an identifier other than the supported Timestamp variants (e.g. custom LogicalType implementations, Enumeration, FixedBytes-adjacent logical types depending on branch).

Common situations: Custom LogicalType subclasses registered on Beam schemas; schemas ported from other frameworks with unsupported logical annotations; upgrading Beam and passing logical types the Avro converter never implemented.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/9867cd8966a47628. Report an issue: GitHub.