apache/beam · error · RuntimeException

Unhandled logical type

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.

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.

Appendix: 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)