apache/beam · error · ClassCastException

Value is not valid for DisplayData type %s: %s

Error message

Value is not valid for DisplayData type %s: %s

What it means

DisplayData.item()/named() value helpers call checkType() to assert the runtime value matches the DisplayData.Type it is being registered as (e.g. a Java class registered as DisplayData.Type.CLASS). If value.getClass() is not assignable to the expected class, a ClassCastException is thrown with this message. It indicates the wrong display-data registration method was used for the value's type.

Source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/display/DisplayData.java:627

    },
    DURATION {
      @Override
      FormattedItemValue format(Object value) {
        Duration duration = checkType(value, Duration.class, DURATION);
        return new FormattedItemValue(duration.getMillis());
      }
    },
    JAVA_CLASS {
      @Override
      FormattedItemValue format(Object value) {
        Class<?> clazz = checkType(value, Class.class, JAVA_CLASS);
        return new FormattedItemValue(clazz.getName(), ReflectHelpers.getSimpleName(clazz));
      }
    };

    private static <T> T checkType(Object value, Class<T> clazz, DisplayData.Type expectedType) {
      if (!clazz.isAssignableFrom(value.getClass())) {
        throw new ClassCastException(
            String.format("Value is not valid for DisplayData type %s: %s", expectedType, value));
      }

      @SuppressWarnings("unchecked") // type checked above.
      T typedValue = (T) value;
      return typedValue;
    }

    /**
     * Format the display data value into a long string representation, and optionally a shorter
     * representation for display.
     *
     * <p>Internal-only. Value objects can be safely cast to the expected Java type.
     */
    abstract FormattedItemValue format(Object value);

    /**
     * Safe version of {@link Type#format(Object)}, which checks for null input value and if so

View on GitHub (pinned to 12126d8942)

Solutions

  1. Match the registration method to the value type (item(String) for strings, instant(Instant), duration(Duration/ReadableDuration), etc.)
  2. Convert the value before registering (e.g. value.toString() if you want it as a STRING item)
  3. Update populateDisplayData after changing field types
  4. Catch ClassCastException in test harnesses that exercise populateDisplayData to catch mismatches in unit tests

Example fix

// before
builder.add(DisplayData.item("deadline", DisplayData.Type.INSTANT, "2024-01-01T00:00:00Z")); // String
// after
builder.add(DisplayData.item("deadline", DisplayData.Type.INSTANT, Instant.parse("2024-01-01T00:00:00Z")));
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(value instanceof Instant)) { throw new IllegalArgumentException("instant() requires an Instant"); }

Type guard

static <T> boolean isAssignable(Object value, Class<T> clazz) { return value != null && clazz.isAssignableFrom(value.getClass()); }

Try / catch

try { builder.add(DisplayData.item(key, DisplayData.Type.INSTANT, value)); } catch (ClassCastException e) { /* register as STRING via toString() instead */ }

Prevention

When it happens

Trigger: In a DoFn/transform's populateDisplayData(builder), calling e.g. DisplayData.instant(value) or DisplayData.duration(value) or clazz-registration with an object of the wrong runtime type — e.g. passing a String where an Instant is required, or a non-Class object where a Class is expected.

Common situations: Refactoring a transform's field types without updating populateDisplayData; copy-pasting display data registration lines between transforms; passing boxed types vs primitives mismatch.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/4b108f7c3a779642. Report an issue: GitHub.