{"record":{"id":"2f4f7c9ecaa3609d","repo":"pinpoint-apm/pinpoint","slug":"otlptraceparseexception-message-from-e-getmessage","errorCode":null,"errorMessage":"OtlpTraceParseException (message from e.getMessage())","messagePattern":"OtlpTraceParseException \\(message from e\\.getMessage\\(\\)\\)","errorType":"http","errorClass":"OtlpTraceParseException","httpStatus":400,"severity":"error","filePath":"otlptrace/otlptrace-collector/src/main/java/com/navercorp/pinpoint/otlp/trace/collector/controller/OtlpJsonTraceParser.java","lineNumber":77,"sourceCode":"            \"spanId\", \"span_id\",\n            \"parentSpanId\", \"parent_span_id\");\n\n    private static final JsonFactory JSON_FACTORY = new JsonFactory();\n    private static final JsonFormat.Parser PROTO_JSON_PARSER = JsonFormat.parser().ignoringUnknownFields();\n\n    private OtlpJsonTraceParser() {\n    }\n\n    public static ExportTraceServiceRequest parse(byte[] body) {\n        try {\n            final String protoJson = rewriteIdsToBase64(body);\n            final ExportTraceServiceRequest.Builder builder = ExportTraceServiceRequest.newBuilder();\n            PROTO_JSON_PARSER.merge(protoJson, builder);\n            return builder.build();\n        } catch (JsonProcessingException e) {\n            throw new OtlpTraceParseException(syntaxErrorMessage(e), e);\n        } catch (IOException | IllegalArgumentException e) {\n            throw new OtlpTraceParseException(e.getMessage(), e);\n        }\n    }\n\n    /**\n     * Jackson's {@link JsonProcessingException#getMessage()} appends the full {@code JsonLocation}\n     * ({@code [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1,\n     * column: 19]}), sometimes twice, which more than doubles the message without adding anything a\n     * client can act on. Keep the cause and the position only — in the shape the OTel collector's\n     * own JSON errors take.\n     */\n    static String syntaxErrorMessage(JsonProcessingException e) {\n        // The original message can embed a location too (\"(for Array starting at [Source: ...])\").\n        final String original = SOURCE_LOCATION.matcher(e.getOriginalMessage()).replaceAll(\"line $1, column $2\");\n        final JsonLocation location = e.getLocation();\n        if (location == null) {\n            return original;\n        }\n        return original + \" (line \" + location.getLineNr() + \", column \" + location.getColumnNr() + \")\";","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/otlptrace/otlptrace-collector/src/main/java/com/navercorp/pinpoint/otlp/trace/collector/controller/OtlpJsonTraceParser.java#L59-L95","documentation":"Same parse() path as the JSON syntax error, but this throw wraps IOException | IllegalArgumentException from the protobuf JSON merge. The message is the underlying e.getMessage(); the javadoc notes Jackson appends the full JsonLocation (source content) to JsonProcessingException messages, so the server deliberately redacts the source. Any I/O problem reading the body or illegal argument during proto JSON parsing surfaces here as OtlpTraceParseException.","triggerScenarios":"Request body stream fails mid-read (IOException), or the merged JSON is structurally parseable but violates proto JSON rules (IllegalArgumentException): e.g. invalid enum string, wrong wire representation of bytes/int64, or a null where a message is required.","commonSituations":"Client sends a partially valid OTLP JSON document (e.g. invalid enum value like a non-existent SpanKind); interrupted connections; bodies exceeding internal limits cut mid-stream; sending numbers as strings where proto JSON disallows it.","solutions":["Fix the OTLP JSON content per the embedded message — most commonly an invalid enum name or wrongly typed field; regenerate with the official protobuf JSON printer.","Ensure the client completes the HTTP request without aborting the body stream (check timeouts/proxy buffering limits).","Validate enums and field types client-side against the opentelemetry-proto schema before export.","If ids/bytes fields are the problem, base64-encode them as required by proto3 JSON mapping."],"exampleFix":"// before\nspan.setKind(\"SPAN_KIND_INTERNAL_X\"); // invalid enum -> IllegalArgumentException in merge\n// after\nspan.setKind(Span.SpanKind.SPAN_KIND_INTERNAL);","handlingStrategy":"try-catch","validationCode":"// client-side pre-check of proto-JSON rules\nEnumVerifier.getDescriptor().verify(value) // or verify enum names/types against opentelemetry-proto descriptors before export","typeGuard":"static boolean hasValidEnumNames(ExportTraceServiceRequest req) {\n    return req.getResourceSpansList().stream()\n        .allMatch(rs -> rs.getScopeSpansList().stream()\n            .allMatch(ss -> ss.getSpansList().stream()\n                .allMatch(s -> Span.SpanKind.forNumber(s.getKindValue()) != null)));\n}","tryCatchPattern":"try {\n    ExportTraceServiceRequest req = parse(body);\n} catch (OtlpTraceParseException e) {\n    if (e.getCause() instanceof IOException) { retryLater(); }          // transport issue\n    else { log.error(\"invalid OTLP proto JSON: {}\", e.getMessage()); }   // content issue\n}","preventionTips":["Generate requests via protobuf-generated classes only","Keep HTTP clients/proxies from truncating or re-encoding bodies","Match field types exactly to proto3 JSON mapping (strings for int64, base64 for bytes)","Pin client and collector to compatible opentelemetry-proto versions"],"tags":["java","otlp","protobuf","json","http"],"backgroundTag":"protobuf-unmarshal-failed","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"}