Tencent/matrix · error · IllegalArgumentException
bad value type
Error message
bad value type: ${value.getClass().getName()} What it means
IOUtil.writeValue serializes a value to an hprof-backed output stream, supporting only Boolean, Character, Byte, Short, Integer and Long. If the value's runtime type is anything else (e.g. Float, Double, String, or an unexpected boxed object), it throws IllegalArgumentException. This is an internal type contract for hprof record value writing; the library only knows how to BE-encode those primitive widths.
Solutions
- Cast or convert the value to a supported type (Boolean, Character, Byte, Short, Integer, Long) before writing.
- If the value is Float/Double, convert via Float.floatToIntBits / Double.doubleToLongBits and write as int/long.
- For strings or complex data, use the hprof string/byte-array record APIs instead of writeValue.
- Check the calling record-building code for a type-mapping bug introduced by recent changes.
Example fix
// before IOUtil.writeValue(out, 3.14f); // after IOUtil.writeBEInt(out, Float.floatToIntBits(3.14f));
Defensive patterns
Strategy: validation
Validate before calling
if (!(value instanceof Boolean || value instanceof Character || value instanceof Byte || value instanceof Short || value instanceof Integer || value instanceof Long)) {
throw new IllegalArgumentException("Unsupported hprof value type: " + value.getClass());
}
IOUtil.writeValue(out, value); Type guard
static boolean isWritableHprofValue(Object v) {
return v instanceof Boolean || v instanceof Character || v instanceof Byte
|| v instanceof Short || v instanceof Integer || v instanceof Long;
} Try / catch
try {
IOUtil.writeValue(out, value);
} catch (IllegalArgumentException e) {
Log.w(TAG, "Unsupported value type, skipping", e);
} Prevention
- Only pass boxed primitives from the supported set to writeValue
- Convert floats/doubles with floatToIntBits/doubleToLongBits before writing
- Use string/byte-array record APIs for non-primitive data
When it happens
Trigger: Calling HprofBufferWriter/IOUtil.writeValue (directly or via hprof record building in matrix-resource-canary) with a value whose class is not one of the supported wrapper types, e.g. passing a Float, Double, String or custom object where a primitive boxed value is expected.
Common situations: Custom hprof record construction or patched/forked code writing new record types with unsupported value types; version drift where a record format expects a type the writer doesn't handle; reflection-based value extraction returning an unexpected boxed type.
Related errors
- Unexpected type for
- visit bmp instance failed, lost type def of typeId:
- visit string instance failed, lost type def of typeId:
- visit instance failed, lost type def of typeId:
- accept class failed, lost type def of typeId:
AI-assisted analysis of Tencent/matrix@3b8293bd65 (2026-09-08).
Data as JSON: /api/errors/d99602f78db11275.
Report an issue: GitHub.
Appendix: source
Thrown at matrix/matrix-android/matrix-resource-canary/matrix-resource-canary-android/src/main/java/com/tencent/matrix/resource/hproflib/utils/IOUtil.java:264
IOUtil.writeID(out, (ID) value);
} else if (value instanceof Boolean || boolean.class.isAssignableFrom(value.getClass())) {
out.write((boolean) value ? 1 : 0);
} else if (value instanceof Character || char.class.isAssignableFrom(value.getClass())) {
IOUtil.writeBEShort(out, (char) value);
} else if (value instanceof Float || float.class.isAssignableFrom(value.getClass())) {
IOUtil.writeBEInt(out, Float.floatToRawIntBits((Float) value));
} else if (value instanceof Double || double.class.isAssignableFrom(value.getClass())) {
IOUtil.writeBELong(out, Double.doubleToRawLongBits((Double) value));
} else if (value instanceof Byte || byte.class.isAssignableFrom(value.getClass())) {
out.write((byte) value);
} else if (value instanceof Short || short.class.isAssignableFrom(value.getClass())) {
IOUtil.writeBEShort(out, (short) value);
} else if (value instanceof Integer || int.class.isAssignableFrom(value.getClass())) {
IOUtil.writeBEInt(out, (int) value);
} else if (value instanceof Long || long.class.isAssignableFrom(value.getClass())) {
IOUtil.writeBELong(out, (long) value);
} else {
throw new IllegalArgumentException("bad value type: " + value.getClass().getName());
}
}
public static void skip(OutputStream out, long size) throws IOException {
final byte[] emptyBuf = new byte[4096];
for (int i = 0; i < (size >> 12); ++i) {
out.write(emptyBuf);
}
out.write(emptyBuf, 0, (int) (size & ((1L << 12) - 1)));
}
private IOUtil() {
throw new UnsupportedOperationException();
}
}
View on GitHub (pinned to 3b8293bd65)