From 09d057b534e6d6edb89ef961e5a6faca7e0230a4 Mon Sep 17 00:00:00 2001 From: Kunal Sevkani Date: Thu, 7 May 2026 20:20:04 +0530 Subject: [PATCH] AVRO-4253: Avoid logging datum values in UnresolvedUnionException message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UnresolvedUnionException previously included the string representation of the unresolved datum in its exception message. When this exception propagates to generic error handlers (e.g. in Kafka Connect runtime), the datum value — which may contain sensitive user data — gets written to log files. Replace the datum's toString() with its class name in the exception message. The actual datum object remains accessible via getUnresolvedDatum() for callers that need it for programmatic use. --- .../java/org/apache/avro/UnresolvedUnionException.java | 9 +++++++-- .../org/apache/avro/generic/TestGenericDatumWriter.java | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lang/java/avro/src/main/java/org/apache/avro/UnresolvedUnionException.java b/lang/java/avro/src/main/java/org/apache/avro/UnresolvedUnionException.java index 8f25c2cc9a8..1e11a4967af 100644 --- a/lang/java/avro/src/main/java/org/apache/avro/UnresolvedUnionException.java +++ b/lang/java/avro/src/main/java/org/apache/avro/UnresolvedUnionException.java @@ -24,13 +24,14 @@ public class UnresolvedUnionException extends AvroRuntimeException { private Schema unionSchema; public UnresolvedUnionException(Schema unionSchema, Object unresolvedDatum) { - super("Not in union " + unionSchema + ": " + unresolvedDatum); + super("Not in union " + unionSchema + ": " + datumTypeDescription(unresolvedDatum)); this.unionSchema = unionSchema; this.unresolvedDatum = unresolvedDatum; } public UnresolvedUnionException(Schema unionSchema, Schema.Field field, Object unresolvedDatum) { - super("Not in union " + unionSchema + ": " + unresolvedDatum + " (field=" + field.name() + ")"); + super( + "Not in union " + unionSchema + ": " + datumTypeDescription(unresolvedDatum) + " (field=" + field.name() + ")"); this.unionSchema = unionSchema; this.unresolvedDatum = unresolvedDatum; } @@ -42,4 +43,8 @@ public Object getUnresolvedDatum() { public Schema getUnionSchema() { return unionSchema; } + + private static String datumTypeDescription(Object datum) { + return datum == null ? "null" : datum.getClass().getName(); + } } diff --git a/lang/java/avro/src/test/java/org/apache/avro/generic/TestGenericDatumWriter.java b/lang/java/avro/src/test/java/org/apache/avro/generic/TestGenericDatumWriter.java index dc3661f467b..03123ffcf86 100644 --- a/lang/java/avro/src/test/java/org/apache/avro/generic/TestGenericDatumWriter.java +++ b/lang/java/avro/src/test/java/org/apache/avro/generic/TestGenericDatumWriter.java @@ -56,7 +56,7 @@ void unionUnresolvedExceptionExplicitWhichField() throws IOException { new GenericDatumWriter<>(s).write(r, EncoderFactory.get().jsonEncoder(s, bao)); fail(); } catch (final UnresolvedUnionException uue) { - assertEquals("Not in union [\"null\",\"string\"]: 100 (field=f)", uue.getMessage()); + assertEquals("Not in union [\"null\",\"string\"]: java.lang.Integer (field=f)", uue.getMessage()); } }