pinpoint-apm/pinpoint · error · IllegalArgumentException
truncated outServiceUid tail, remaining:${remaining}
Error message
truncated outServiceUid tail, remaining:${remaining} What it means
UidLinkRowKey.getOutServiceUid deserializes the trailing outServiceUid int from the row-key ByteBuffer. A remaining slice of 1-3 bytes means the buffer is truncated (readInt needs exactly 4 bytes and does not itself bound-check), so an IllegalArgumentException is thrown to fail fast instead of reading garbage or underflowing.
Source
Thrown at commons-server/src/main/java/com/navercorp/pinpoint/common/server/applicationmap/statistics/UidLinkRowKey.java:189
String outApplicationName = buffer.readPrefixedString();
String outSubLink = buffer.readPrefixedString();
// tail-appended link serviceUid; absent in legacy rows -> assume DEFAULT service (no non-DEFAULT legacy data exists)
int outServiceUid = getOutServiceUid(buffer);
return new UidLinkRowKey(serviceUid, applicationName, serviceType,
timestamp,
outServiceUid, outApplicationName, outServiceType, outSubLink);
}
private static int getOutServiceUid(Buffer buffer) {
final int remaining = buffer.remaining();
if (remaining == 0) {
return ServiceUid.DEFAULT_SERVICE_UID_CODE;
}
// fail fast on a truncated tail: readInt() does not check the slice bound
if (remaining < BytesUtils.INT_BYTE_LENGTH) {
throw new IllegalArgumentException("truncated outServiceUid tail, remaining:" + remaining);
}
return buffer.readInt();
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
UidLinkRowKey that = (UidLinkRowKey) o;
return serviceUid == that.serviceUid && serviceType == that.serviceType && timestamp == that.timestamp && linkServiceType == that.linkServiceType && linkServiceUid == that.linkServiceUid && Objects.equals(applicationName, that.applicationName) && Objects.equals(linkApplicationName, that.linkApplicationName) && Objects.equals(subLink, that.subLink);
}
@Override
public int hashCode() {
int result = serviceUid;
result = 31 * result + Objects.hashCode(applicationName);
result = 31 * result + serviceType;View on GitHub (pinned to 744c3d3075)
Solutions
- Check that the writer and reader use the same UidLink row-key schema/version (keys that include outServiceUid)
- Verify the stored byte array length matches the expected key size before constructing the row key
- Regenerate or repair affected rows; treat 1-3-byte-tail keys as legacy and fall back to the default service uid path
- Guard with buffer.remaining() >= BytesUtils.INT_BYTE_LENGTH before attempting to read the tail
Example fix
// before
UidLinkRowKey key = UidLinkRowKey.read(bytes);
// after
if (bytes == null || (bytes.length % keyUnit) != 0 || bytes.length < minKeyLength) {
throw new IllegalArgumentException("unexpected UidLink key length: " + (bytes == null ? -1 : bytes.length));
}
UidLinkRowKey key = UidLinkRowKey.read(bytes); Defensive patterns
Strategy: try-catch
Validate before calling
boolean isWellFormedUidLinkKey(byte[] rowKey, int expectedTailBytes) {
return rowKey != null && rowKey.length >= expectedTailBytes;
} Type guard
boolean isWellFormedUidLinkKey(byte[] rowKey, int expectedTailBytes) {
return rowKey != null && rowKey.length >= expectedTailBytes;
} Try / catch
try {
long outServiceUid = rowKey.getOutServiceUid();
} catch (IllegalArgumentException e) {
log.warn("truncated UidLink key, treating as legacy: {}", e.getMessage());
long outServiceUid = ServiceUid.DEFAULT_SERVICE_UID_CODE; // legacy fallback
} Prevention
- Keep writer and reader row-key schema versions in sync
- Validate byte-array lengths against the expected key layout before parsing
- Handle legacy keys (without outServiceUid tail) with an explicit code path
- Detect storage corruption/migration issues early with key-length assertions
When it happens
Trigger: Reading a UidLink row key whose serialized bytes are shorter than expected: a key persisted by a schema/version without the outServiceUid tail, or a byte array that was cut off during storage/transfer, with 1-3 bytes left at the tail.
Common situations: Version mismatch between writer and reader of LinkRowKeys (schema evolved to append outServiceUid); data migrated from older tables; hand-built byte arrays passed to the row key parser; corrupted HBase cells.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Connection already closed
- Invalid namespace : <namespace>
- Already closed
- HBase version compatibility violation HBaseClient:%s, HBaseS
- Unknown HbaseClientVersion:<version>
AI-assisted analysis of pinpoint-apm/pinpoint@744c3d3075 (2026-09-07).
Data as JSON: /api/errors/e04b03e35f638c30.
Report an issue: GitHub.