pinpoint-apm/pinpoint · error · TProtocolException

Invalid pinpoint header type

Error message

Invalid pinpoint header type - ${headerType}

What it means

ThriftRequestProperty.setTraceHeader validates that the declared TType of a pinpoint propagation header matches a supported set (BYTE, I32, I64, I16, BOOL, STRING). If the headerType argument is any other Thrift type, it throws TProtocolException. This guards against writing propagation metadata with an incompatible wire type.

Solutions

  1. Use only supported TTypes for pinpoint headers: BYTE, I32, I64, I16, BOOL, STRING
  2. Verify each ThriftHeader constant's declared TType matches the value type you pass
  3. Check plugin/version consistency between client and server propagation code
  4. Log the offending headerType and fix the header definition

Example fix

// before
request.setTraceHeader(ThriftHeader.HTTP_TRACE_ID, TType.DOUBLE, traceId);
// after
request.setTraceHeader(ThriftHeader.HTTP_TRACE_ID, TType.I64, traceId);
Defensive patterns

Strategy: validation

Validate before calling

private static final Set<Byte> SUPPORTED = Set.of(TType.BYTE, TType.I32, TType.I64, TType.I16, TType.BOOL, TType.STRING);
if (!SUPPORTED.contains(headerType)) {
    throw new IllegalArgumentException("unsupported pinpoint header TType: " + headerType);
}
if (value == null) {
    throw new IllegalArgumentException("pinpoint header value must not be null");
}

Type guard

boolean isSupportedHeaderType(byte t) {
    return t == TType.BYTE || t == TType.I32 || t == TType.I64 || t == TType.I16 || t == TType.BOOL || t == TType.STRING;
}

Try / catch

try {
    property.setTraceHeader(header, headerType, value);
} catch (TProtocolException e) {
    logger.warn("bad header type {} for {}", headerType, header, e);
}

Prevention

When it happens

Trigger: Calling setTraceHeader(ThriftHeader, TType, Object) with a TType outside the supported list (e.g. TType.DOUBLE, TType.LIST) or a value whose runtime type does not match headerType, causing the cast/put branch chain to fall through to the else throw.

Common situations: Custom pinpoint header registration using a wrong TType constant; copy-paste of a ThriftHeader definition with the wrong type; version mismatch where a header was redefined to an unsupported type.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at agent-module/plugins/thrift/src/main/java/com/navercorp/pinpoint/plugin/thrift/ThriftRequestProperty.java:203

    
    public void setAcceptorHost(String acceptorHost) {
        this.thriftHeaders.put(ThriftHeader.THRIFT_HOST, acceptorHost);
    }
    
    public void setTraceHeader(ThriftHeader headerKey, Object value) throws TException {
        byte headerType = headerKey.getType();
        if (headerType == TType.STRING) {
            // skipped Strings are read as byte buffer.
            // see org.apache.thrift.protocol.TProtocolUtil.skip(TProtocol, byte, int)
            this.thriftHeaders.put(headerKey, byteBufferToString((ByteBuffer)value));
        } else if (headerType == TType.I64) {
            this.thriftHeaders.put(headerKey, (Long)value);
        } else if (headerType == TType.I16) {
            this.thriftHeaders.put(headerKey, (Short)value);
        } else if (headerType == TType.BOOL) {
            this.thriftHeaders.put(headerKey, (Boolean)value);
        } else {
            throw new TProtocolException("Invalid pinpoint header type - " + headerType);
        }
    }
    
    public void writeTraceHeader(ThriftHeader headerKey, TProtocol oprot) throws TException {
        Object headerValue = this.thriftHeaders.get(headerKey);
        if (headerValue == null) {
            return;
        }
        byte headerType = headerKey.getType();
        TField traceField = new TField(headerKey.name(), headerKey.getType(), headerKey.getId());
        oprot.writeFieldBegin(traceField);
        try {
            if (headerType == TType.STRING) {
                // these will be read as byte buffer although it's probably safe to just use writeString here.
                // see org.apache.thrift.protocol.TProtocolUtil.skip(TProtocol, byte, int)
                oprot.writeBinary(stringToByteBuffer((String)headerValue));
            } else if (headerType == TType.I64) {
                oprot.writeI64((Long)headerValue);

View on GitHub (pinned to 744c3d3075)