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

  1. Ensure every value passed to writeValue is non-null and of a supported type (ID, Boolean, Character, numeric).
  2. Filter or substitute nulls before serialization (e.g. write Type.OBJECT null reference as an ID of 0).
  3. 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

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


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)