{"record":{"id":"e1bb051a00d7ceb0","repo":"pinpoint-apm/pinpoint","slug":"unsupported-type-datatype","errorCode":null,"errorMessage":"unsupported type:${dataType}","messagePattern":"unsupported type:(.+?)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/grpc/mapper/AnnotationValueMapper.java","lineNumber":206,"sourceCode":"            builder.setIntStringStringValue(pIntStringStringValue);\n            return builder.build();\n        } else if (dataType instanceof LongIntIntByteByteStringValue) {\n            final LongIntIntByteByteStringValue v = (LongIntIntByteByteStringValue) dataType;\n            final PLongIntIntByteByteStringValue pValue = map(v);\n            builder.setLongIntIntByteByteStringValue(pValue);\n            return builder.build();\n        } else if (dataType instanceof IntBooleanIntBooleanValue) {\n            final IntBooleanIntBooleanValue v = (IntBooleanIntBooleanValue) dataType;\n            final PIntBooleanIntBooleanValue pValue = map(v);\n            builder.setIntBooleanIntBooleanValue(pValue);\n            return builder.build();\n        } else if (dataType instanceof BytesStringStringValue) {\n            final BytesStringStringValue v = (BytesStringStringValue) dataType;\n            PBytesStringStringValue pValue = map(v);\n            builder.setBytesStringStringValue(pValue);\n            return builder.build();\n        }\n        throw new UnsupportedOperationException(\"unsupported type:\" + dataType);\n    }\n\n    @InheritConfiguration(name = \"dummyForIgnoreMapping\")\n    PIntStringValue map(IntStringValue v);\n\n    @InheritConfiguration(name = \"dummyForIgnoreMapping\")\n    PStringStringValue map(StringStringValue v);\n\n    @InheritConfiguration(name = \"dummyForIgnoreMapping\")\n    PIntStringStringValue map(IntStringStringValue v);\n\n    @InheritConfiguration(name = \"dummyForIgnoreMapping\")\n    @Mapping(source = \"intValue2\", target = \"intValue2\", conditionQualifiedByName = \"isNotMinusInt\")\n    @Mapping(source = \"byteValue1\", target = \"byteValue1\", conditionQualifiedByName = \"isNotMinusByte\")\n    @Mapping(source = \"byteValue2\", target = \"byteValue2\", conditionQualifiedByName = \"isNotMinusByte\")\n    PLongIntIntByteByteStringValue map(LongIntIntByteByteStringValue v);\n\n","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/context/grpc/mapper/AnnotationValueMapper.java#L188-L224","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use only supported annotation value types (primitives, String, byte[], and the TBytes* typed classes) when recording annotations.","Convert the custom type into a supported one before Annotation.setAnnotationValue — e.g. serialize the object to byte[]/String.","Align versions: update the agent so mapper and plugin API versions match.","Extend AnnotationValueMapper (and the proto) in a fork if a new type must be transported."],"exampleFix":"// before\nannotation.setAnnotationValue(\"MyAnnotation\", myCustomObject); // unsupported type\n\n// after\nannotation.setAnnotationValue(\"MyAnnotation\", String.valueOf(myCustomObject)); // or serialized byte[]","handlingStrategy":"type-guard","validationCode":"static final Set<Class<?>> SUPPORTED = Set.of(\n    String.class, Integer.class, Long.class, Boolean.class, Double.class,\n    Short.class, Float.class, Byte.class, byte[].class /* plus TBytes* types */);\nboolean supported = dataType == null || SUPPORTED.contains(dataType.getClass());","typeGuard":"static boolean isSupportedAnnotationValue(Object v) {\n    return v == null || v instanceof String || v instanceof Number\n            || v instanceof Boolean || v instanceof byte[]\n            || v instanceof TIntStringStringValue || v instanceof TLongBytesStringStringValue\n            || v instanceof TBytesStringStringValue; // extend with all supported types\n}","tryCatchPattern":"try {\n    PAnnotationValue p = AnnotationValueMapper.map(dataType);\n} catch (UnsupportedOperationException e) {\n    logger.warn(\"Dropping unsupported annotation value type: {}\", e.getMessage());\n    // omit annotation value or map to String.valueOf(dataType)\n}","preventionTips":["Only record annotations with documented supported value types.","In custom plugins, serialize complex objects to String/byte[] before Annotation.setAnnotationValue.","Keep plugin API and agent versions aligned to avoid unmapped newer types."],"tags":["java","grpc","unsupported-type","annotations","serialization"],"backgroundTag":"unsupported-operation","analyzedSha":"744c3d3075e595656abb1ae331ad2c0e4c9eb996","analyzedAt":"2026-09-07T18:48:45.289Z","contentChangedAt":"2026-09-07T18:48:45.289Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}