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
- Use only supported TTypes for pinpoint headers: BYTE, I32, I64, I16, BOOL, STRING
- Verify each ThriftHeader constant's declared TType matches the value type you pass
- Check plugin/version consistency between client and server propagation code
- 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
- Define each ThriftHeader constant with its TType and value type together to keep them in sync
- Only use TType constants from the supported list when registering pinpoint headers
- Add a unit test that round-trips every custom header through setTraceHeader/writeTraceHeader
- Keep agent/plugin versions consistent across services
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
- absolute start/end time is only supported for TRACE_V3 span…
- agentInfoRefreshIntervalMs must be greater than 0
- agentInfoSendIntervalMs must be greater than 0
- annotationKey name must not be empty
- customMetricName must consist of
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)