microg/GmsCore · error · ReadException

Expected object header. Got 0x" + Integer.toHexString(header

Error message

Expected object header. Got 0x" + Integer.toHexString(header)

What it means

SafeParcelReader.readObjectHeader() (used by readStart) verifies that the header it reads is an object-start marker (SAFE_PARCEL_OBJECT_MAGIC) and throws ReadException 'Expected object header. Got 0x...' when the field id in the header does not match. It also validates the size/end position against the Parcel bounds. This indicates the stream is misaligned or was not written by SafeParcelable serialization.

Source

Thrown at play-services-basement/src/main/java/com/google/android/gms/common/internal/safeparcel/SafeParcelReader.java:62

    }

    private static void readExpectedSize(Parcel parcel, int header, int expectedSize) {
        int i = readSize(parcel, header);
        if (i != expectedSize)
            throw new ReadException("Expected size " + expectedSize + " got " + i + " (0x" + Integer.toHexString(i) + ")", parcel);
    }

    @Deprecated
    public static int readStart(Parcel parcel) {
        return readObjectHeader(parcel);
    }

    public static int readObjectHeader(Parcel parcel) {
        int header = readHeader(parcel);
        int size = readSize(parcel, header);
        int start = parcel.dataPosition();
        if (getFieldId(header) != SafeParcelable.SAFE_PARCEL_OBJECT_MAGIC)
            throw new ReadException("Expected object header. Got 0x" + Integer.toHexString(header), parcel);
        int end = start + size;
        if ((end < start) || (end > parcel.dataSize()))
            throw new ReadException("Size read is invalid start=" + start + " end=" + end, parcel);
        return end;
    }

    public static int readInt(Parcel parcel, int header) {
        readExpectedSize(parcel, header, 4);
        return parcel.readInt();
    }

    public static byte readByte(Parcel parcel, int header) {
        readExpectedSize(parcel, header, 4);
        return (byte) parcel.readInt();
    }

    public static short readShort(Parcel parcel, int header) {
        readExpectedSize(parcel, header, 4);

View on GitHub (pinned to 157c9d86ac)

Solutions

  1. Verify the Parcel was written by SafeParcelable serialization and read from position 0
  2. Ensure writer and reader classes/versions match
  3. Check that no fields were consumed before readStart()
  4. Catch ReadException and fall back to alternative parsing

Example fix

// before
int end = SafeParcelReader.readStart(parcel); // parcel position misaligned
// after
try {
    int end = SafeParcelReader.readStart(parcel);
} catch (SafeParcelReader.ReadException e) {
    throw new IllegalArgumentException("Not a SafeParcelable parcel", e);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure parcel.dataPosition() == 0 and data written by SafeParcelable before readStart()

Try / catch

try { int end = SafeParcelReader.readStart(parcel); } catch (SafeParcelReader.ReadException e) { handleMalformedHeader(e); }

Prevention

When it happens

Trigger: Calling SafeParcelReader.readStart(parcel) on a Parcel whose next object is not a SafeParcel object header, e.g. a plain Bundle, wrong dataPosition, or extra/missing fields causing misalignment.

Common situations: Reading a Parcel from a different starting offset; parsing Parcels written by non-SafeParcelable code; version skew between writer and reader field counts.

Understand the failure class

Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.

Related errors


AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06). Data as JSON: /api/errors/e01a5e42e8c928fb. Report an issue: GitHub.