Tencent/matrix · error · IllegalArgumentException
value is null.
Error message
value is null.
What it means
IOUtil.writeValue() serializes a hprof primitive/ID value to an OutputStream but rejects null with IllegalArgumentException. Null is not representable in the hprof value encoding (every field has a concrete type and byte representation), so the caller must supply a typed value.
Solutions
- Ensure every value passed to writeValue is non-null and of a supported type (ID, Boolean, Character, numeric).
- Filter or substitute nulls before serialization (e.g. write Type.OBJECT null reference as an ID of 0).
- Add an explicit null check at the call site with a descriptive error naming the field.
Example fix
// before
IOUtil.writeValue(out, fieldValue);
// after
if (fieldValue == null) {
// represent null reference as id 0
IOUtil.writeValue(out, new ID(new byte[idSize]));
} else {
IOUtil.writeValue(out, fieldValue);
} Defensive patterns
Strategy: validation
Validate before calling
static void requireWritableValue(Object v) {
if (v == null) throw new IllegalArgumentException("hprof value must be non-null; use ID(0) for null reference");
} Type guard
static boolean isWritableValue(Object v) {
return v instanceof ID || v instanceof Boolean || v instanceof Character
|| v instanceof Byte || v instanceof Short || v instanceof Integer
|| v instanceof Long || v instanceof Float || v instanceof Double;
} Try / catch
try {
IOUtil.writeValue(out, value);
} catch (IllegalArgumentException e) {
if ("value is null.".equals(e.getMessage())) {
IOUtil.writeValue(out, new ID(new byte[idSize])); // null reference
}
} Prevention
- Never serialize raw map values without null-filtering
- Represent null references as a zero ID matching the hprof idSize
- Type-check values against supported hprof basic types before writing
When it happens
Trigger: Calling writeValue with a null Object when re-serializing hprof values; analysis code building synthetic class/instance dumps with unset fields; map iteration over values that contain null entries.
Common situations: Custom hprof rewriting/trimming tools built on hproflib that pass through unboxed values from collections containing nulls; deserialized models with missing primitive fields.
Related errors
- Unable to obtained scaled bitmap's dimensions
- Could not find char array in
- Field does not exists
- Unabled to find destroy activity info class with name:
- Could not find weak reference with key
AI-assisted analysis of Tencent/matrix@3b8293bd65 (2026-09-08).
Data as JSON: /api/errors/347b9c84f115595e.
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:244
}
public static void writeString(OutputStream out, String text) throws IOException {
final int length = text.length();
out.write(text.getBytes(Charset.forName("UTF-8")), 0, length);
}
public static void writeNullTerminatedString(OutputStream out, String text) throws IOException {
out.write(text.getBytes(Charset.forName("UTF-8")));
out.write(0);
}
public static void writeID(OutputStream out, ID id) throws IOException {
out.write(id.getBytes());
}
public static void writeValue(OutputStream out, Object value) throws IOException {
if (value == null) {
throw new IllegalArgumentException("value is null.");
} else if (value instanceof ID) {
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);View on GitHub (pinned to 3b8293bd65)