microg/GmsCore · error · RuntimeException

Error writing %s

Error message

Error writing %s

What it means

SafeParcelProcessor's generated `writeToParcel` wraps variable declaration and field-to-parcel writing in try/catch and rethrows as RuntimeException("Error writing <class>", e). It marks which @SafeParcelable class failed to serialize; the cause reveals the offending field (unsupported type, throwing getter, null that cannot be written, etc.).

Source

Thrown at safe-parcel-processor/src/main/kotlin/org/microg/safeparcel/SafeParcelProcessor.kt:184

                            $setFieldsFromVariables
                        } catch (Exception e) {
                            throw new RuntimeException(String.format("Error reading %s", "$fullName"), e);
                        }
                        if (parcel.dataPosition() > end) {
                            throw new RuntimeException(String.format("Overread allowed size end=%d", end));
                        }
                        return object;
                    }

                    @Override
                    public void writeToParcel($fullName object, $Parcel parcel, int flags) {
                        int start = $SafeParcelWriter.writeObjectHeader(parcel);
                        try {
                            $variableDeclarations
                            $setVariablesFromFields
                            $writeVariableToParcel
                        } catch (Exception e) {
                            throw new RuntimeException(String.format("Error writing %s", "$fullName"), e);
                        }
                        $SafeParcelWriter.finishObjectHeader(parcel, start);
                    }

                    @Override
                    public $fullName[] newArray(int size) {
                        return new $fullName[size];
                    }
                }
            """.trimIndent()
        return file
    }
}

class ConstructorInfo(val clazz: ClassInfo, val constructorElement: ExecutableElement) {
    val isPrivate by lazy { constructorElement.modifiers.contains(Modifier.PRIVATE) }
    val parameters by lazy { constructorElement.parameters }
    val fieldIds by lazy {

View on GitHub (pinned to 157c9d86ac)

Solutions

  1. Read the cause stack trace to identify the failing field
  2. Ensure every @Field has a SafeParcelWriter-supported type and is initialized (non-null or explicitly nullable-safe) before writeToParcel
  3. Fix or remove the nested object that throws during its own writeToParcel
  4. Rebuild the project so generated writer code matches the current class definition

Example fix

// before: uninitialized field blows up on write
@Field(value = 2)
lateinit var config: MyConfig
// after: write nullable with default
@Field(value = 2)
var config: MyConfig? = null
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure all fields are initialized before handing the object to a Parcel
require(!requiresInit || ::config.isInitialized) { "config must be set before parceling" }

Type guard

fun MySafeParcelable.isWritable(): Boolean =
  this::class.declaredMemberProperties.all { p -> (p.getter.call(this) as? Throwable)?.let { false } ?: true }

Try / catch

try {
  dest.writeTypedObject(item, flags)
} catch (e: RuntimeException) {
  if (e.message?.startsWith("Error writing") == true) {
    Log.w(TAG, "SafeParcel write failed", e.cause)
    dest.writeNoOp() // or serialize a fallback representation
  } else throw e
}

Prevention

When it happens

Trigger: Any exception while writing fields of a @SafeParcelable object: a field getter throws, a field value's own writeToParcel fails (nested SafeParcelable/Parcelable with problems), or a field type cannot be represented by SafeParcelWriter.

Common situations: Nested Parcelable whose own serialization breaks; lazily-initialized field that is null or throwing at write time; class refactored with a field type the SafeParcel writer cannot handle; transaction stopped mid-write (rare — usually surfaces differently).

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


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