pinpoint-apm/pinpoint · error · UnsupportedOperationException

unsupported type:${dataType}

Error message

unsupported type:${dataType}

What it means

AnnotationValueMapper.map converts profiler annotation value objects into protobuf message types for gRPC transport. It dispatches on the runtime type of dataType through an if/else chain of known types; if the type is not one of the supported annotation value classes, it throws UnsupportedOperationException with the value's type name. This protects the wire protocol from unmapped data types.

Source

Thrown at agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/grpc/mapper/AnnotationValueMapper.java:206

            builder.setIntStringStringValue(pIntStringStringValue);
            return builder.build();
        } else if (dataType instanceof LongIntIntByteByteStringValue) {
            final LongIntIntByteByteStringValue v = (LongIntIntByteByteStringValue) dataType;
            final PLongIntIntByteByteStringValue pValue = map(v);
            builder.setLongIntIntByteByteStringValue(pValue);
            return builder.build();
        } else if (dataType instanceof IntBooleanIntBooleanValue) {
            final IntBooleanIntBooleanValue v = (IntBooleanIntBooleanValue) dataType;
            final PIntBooleanIntBooleanValue pValue = map(v);
            builder.setIntBooleanIntBooleanValue(pValue);
            return builder.build();
        } else if (dataType instanceof BytesStringStringValue) {
            final BytesStringStringValue v = (BytesStringStringValue) dataType;
            PBytesStringStringValue pValue = map(v);
            builder.setBytesStringStringValue(pValue);
            return builder.build();
        }
        throw new UnsupportedOperationException("unsupported type:" + dataType);
    }

    @InheritConfiguration(name = "dummyForIgnoreMapping")
    PIntStringValue map(IntStringValue v);

    @InheritConfiguration(name = "dummyForIgnoreMapping")
    PStringStringValue map(StringStringValue v);

    @InheritConfiguration(name = "dummyForIgnoreMapping")
    PIntStringStringValue map(IntStringStringValue v);

    @InheritConfiguration(name = "dummyForIgnoreMapping")
    @Mapping(source = "intValue2", target = "intValue2", conditionQualifiedByName = "isNotMinusInt")
    @Mapping(source = "byteValue1", target = "byteValue1", conditionQualifiedByName = "isNotMinusByte")
    @Mapping(source = "byteValue2", target = "byteValue2", conditionQualifiedByName = "isNotMinusByte")
    PLongIntIntByteByteStringValue map(LongIntIntByteByteStringValue v);

View on GitHub (pinned to 744c3d3075)

Solutions

  1. Use only supported annotation value types (primitives, String, byte[], and the TBytes* typed classes) when recording annotations.
  2. Convert the custom type into a supported one before Annotation.setAnnotationValue — e.g. serialize the object to byte[]/String.
  3. Align versions: update the agent so mapper and plugin API versions match.
  4. Extend AnnotationValueMapper (and the proto) in a fork if a new type must be transported.

Example fix

// before
annotation.setAnnotationValue("MyAnnotation", myCustomObject); // unsupported type

// after
annotation.setAnnotationValue("MyAnnotation", String.valueOf(myCustomObject)); // or serialized byte[]
Defensive patterns

Strategy: type-guard

Validate before calling

static final Set<Class<?>> SUPPORTED = Set.of(
    String.class, Integer.class, Long.class, Boolean.class, Double.class,
    Short.class, Float.class, Byte.class, byte[].class /* plus TBytes* types */);
boolean supported = dataType == null || SUPPORTED.contains(dataType.getClass());

Type guard

static boolean isSupportedAnnotationValue(Object v) {
    return v == null || v instanceof String || v instanceof Number
            || v instanceof Boolean || v instanceof byte[]
            || v instanceof TIntStringStringValue || v instanceof TLongBytesStringStringValue
            || v instanceof TBytesStringStringValue; // extend with all supported types
}

Try / catch

try {
    PAnnotationValue p = AnnotationValueMapper.map(dataType);
} catch (UnsupportedOperationException e) {
    logger.warn("Dropping unsupported annotation value type: {}", e.getMessage());
    // omit annotation value or map to String.valueOf(dataType)
}

Prevention

When it happens

Trigger: Recording an annotation whose value object's class is not in the mapper's supported set (e.g. a new/custom annotation value type, or a type added in a newer Pinpoint core than the mapper supports) and then sending the span to the collector via gRPC.

Common situations: Custom plugins adding their own annotation value types; mixing Pinpoint component versions (agent plugin compiled against newer API than mapper); annotation APIs producing types the gRPC mapper was never extended for.

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 pinpoint-apm/pinpoint@744c3d3075 (2026-09-07). Data as JSON: /api/errors/e1bb051a00d7ceb0. Report an issue: GitHub.