pinpoint-apm/pinpoint · error · OtlpTraceParseException

OtlpTraceParseException (syntax error, message built from sy

Error message

OtlpTraceParseException (syntax error, message built from syntaxErrorMessage(e))

What it means

OtlpJsonTraceParser.parse() parses the OTLP/HTTP JSON body into an ExportTraceServiceRequest protobuf via Jackson's ProtoJson parser. A JsonProcessingException (malformed JSON, wrong types, invalid field names) is wrapped as OtlpTraceParseException with a syntax-error message. The request is rejected because it is not valid OTLP JSON.

Source

Thrown at otlptrace/otlptrace-collector/src/main/java/com/navercorp/pinpoint/otlp/trace/collector/controller/OtlpJsonTraceParser.java:75

    private static final Set<String> ID_FIELD_NAMES = Set.of(
            "traceId", "trace_id",
            "spanId", "span_id",
            "parentSpanId", "parent_span_id");

    private static final JsonFactory JSON_FACTORY = new JsonFactory();
    private static final JsonFormat.Parser PROTO_JSON_PARSER = JsonFormat.parser().ignoringUnknownFields();

    private OtlpJsonTraceParser() {
    }

    public static ExportTraceServiceRequest parse(byte[] body) {
        try {
            final String protoJson = rewriteIdsToBase64(body);
            final ExportTraceServiceRequest.Builder builder = ExportTraceServiceRequest.newBuilder();
            PROTO_JSON_PARSER.merge(protoJson, builder);
            return builder.build();
        } catch (JsonProcessingException e) {
            throw new OtlpTraceParseException(syntaxErrorMessage(e), e);
        } catch (IOException | IllegalArgumentException e) {
            throw new OtlpTraceParseException(e.getMessage(), e);
        }
    }

    /**
     * Jackson's {@link JsonProcessingException#getMessage()} appends the full {@code JsonLocation}
     * ({@code [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1,
     * column: 19]}), sometimes twice, which more than doubles the message without adding anything a
     * client can act on. Keep the cause and the position only — in the shape the OTel collector's
     * own JSON errors take.
     */
    static String syntaxErrorMessage(JsonProcessingException e) {
        // The original message can embed a location too ("(for Array starting at [Source: ...])").
        final String original = SOURCE_LOCATION.matcher(e.getOriginalMessage()).replaceAll("line $1, column $2");
        final JsonLocation location = e.getLocation();
        if (location == null) {
            return original;

View on GitHub (pinned to 744c3d3075)

Solutions

  1. Validate the request body with a strict JSON parser and a proto JSON schema check before sending; generate the body with ExportTraceServiceRequest JSON serialization rather than hand-built JSON.
  2. Confirm the client targets the JSON endpoint with Content-Type: application/json (binary protobuf goes to the protobuf endpoint).
  3. Use the error's syntax message (line/column info from Jackson) to locate the malformed portion of the payload.
  4. Ensure all trace/span IDs are base64-encoded when using the JSON format (the server rewrites ids to base64 before parsing).

Example fix

// before
String json = "{\"resourceSpans\": [" + partial + "}"; // hand-built, truncated
// after
String json = JsonFormat.printer().omittingInsignificantWhitespace().print(exportRequest);
Defensive patterns

Strategy: validation

Validate before calling

ObjectMapper om = new ObjectMapper();
try (JsonParser p = om.createParser(body)) {
    while (p.nextToken() != null) {} // syntax check before sending
}

Type guard

static boolean looksLikeOtlpJson(String body) {
    return body != null && body.trim().startsWith("{") && body.contains("resourceSpans");
}

Try / catch

try {
    byte[] resp = sendOtlpJson(body);
} catch (OtlpTraceParseException e) {
    log.error("OTLP JSON rejected: {}", e.getMessage());
    // fix payload or switch to protobuf binary endpoint
}

Prevention

When it happens

Trigger: POSTing a trace export request to the OTLP JSON trace collector endpoint whose body fails JSON parsing: malformed JSON syntax, unknown fields, wrong value types (e.g. string where bytes expected), or IDs encoded other than base64.

Common situations: SDKs or scripts hand-rolling OTLP JSON instead of using protobuf JSON serialization; proxies mangling the body; base64/protobuf binary body sent to the JSON endpoint; truncated request bodies.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of pinpoint-apm/pinpoint@744c3d3075 (2026-09-07). Data as JSON: /api/errors/0c2ddf3c829168da. Report an issue: GitHub.