Skip to content

Redacted non-nullable enum fields generate invalid null assignment in Kotlin #3609

@saiimons

Description

@saiimons

When a proto3 enum field is annotated with a redaction option, the generated Kotlin redact() method assigns null to it, causing a compilation error:

Null can not be a value of a non-null type Country

This is the same class of bug that #1977 fixed for scalar types (String, Int, etc.) in 2021, but enum types were missed. Scalars now correctly use identity values (e.g., "", 0), but enums still fall through to the else -> CodeBlock.of("null") branch in Field.redact().

Reproduction:

syntax = "proto3";

enum Country {
  COUNTRY_INVALID = 0;
  US = 1;
  DE = 2;
}

message MyMessage {
  Country country = 1 [(this.is.redacted) = true];
}

Generated Kotlin:

// country is non-null with a default:
public val country: Country = Country.COUNTRY_INVALID,

// But redact() tries to null it:
override fun redact(value: MyMessage): MyMessage = value.copy(
    country = null, // ← ERROR: Country is non-null
    unknownFields = ByteString.EMPTY
)

Expected behavior:

The redact() method should use the enum's identity value (the zero-value constant) instead of null:

override fun redact(value: MyMessage): MyMessage = value.copy(
    country = Country.COUNTRY_INVALID,
    unknownFields = ByteString.EMPTY
)

Affected code:

In KotlinGenerator.kt, Field.redact():

private fun Field.redact(fieldName: String): CodeBlock? {
  if (isRedacted) {
    return when {
      useArray -> emptyPrimitiveArrayForType
      isRepeated -> CodeBlock.of("emptyList()")
      isMap -> CodeBlock.of("emptyMap()")
      encodeMode!! == EncodeMode.NULL_IF_ABSENT -> CodeBlock.of("null")
      isScalar -> PROTOTYPE_TO_IDENTITY_VALUES[type!!]
      else -> CodeBlock.of("null") // ← enums hit this branch
    }

A fix would add an enum-specific branch before the else, using the enum's first constant (identity/zero value).

Workarounds:

  • Avoid annotating non-optional enum fields with redaction options
  • Pin the proto to a version before the redaction annotation was added

Related: #1977 (same fix for scalars)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions