apache/flink · error · InvalidTypesException

Could not determine TypeInformation for the OutputTag type.

Error message

Could not determine TypeInformation for the OutputTag type. The most common reason is forgetting to make the OutputTag an anonymous inner class. It is also not possible to use generic type variables with OutputTags, such as 'Tuple2<A, B>'.

What it means

OutputTag's no-TypeInformation constructor extracts the side-output type via TypeExtractor at construction time; when extraction fails (InvalidTypesException), it rethrows with this explanatory InvalidTypesException. Type extraction only works for concrete, fully-resolvable generic types — the canonical pattern is an anonymous subclass that fixes the type parameter, e.g. new OutputTag<Tuple2<String, Long>>("id"){}. The message names the two usual causes: non-anonymous usage and generic type variables.

Source

Thrown at flink-core/src/main/java/org/apache/flink/util/OutputTag.java:68

    private final String id;

    private final TypeInformation<T> typeInfo;

    /**
     * Creates a new named {@code OutputTag} with the given id.
     *
     * @param id The id of the created {@code OutputTag}.
     */
    public OutputTag(String id) {
        Preconditions.checkNotNull(id, "OutputTag id cannot be null.");
        Preconditions.checkArgument(!id.isEmpty(), "OutputTag id must not be empty.");
        this.id = id;

        try {
            this.typeInfo = TypeExtractor.createTypeInfo(this, OutputTag.class, getClass(), 0);
        } catch (InvalidTypesException e) {
            throw new InvalidTypesException(
                    "Could not determine TypeInformation for the OutputTag type. "
                            + "The most common reason is forgetting to make the OutputTag an anonymous inner class. "
                            + "It is also not possible to use generic type variables with OutputTags, such as 'Tuple2<A, B>'.",
                    e);
        }
    }

    /**
     * Creates a new named {@code OutputTag} with the given id and output {@link TypeInformation}.
     *
     * @param id The id of the created {@code OutputTag}.
     * @param typeInfo The {@code TypeInformation} for the side output.
     */
    public OutputTag(String id, TypeInformation<T> typeInfo) {
        Preconditions.checkNotNull(id, "OutputTag id cannot be null.");
        Preconditions.checkArgument(!id.isEmpty(), "OutputTag id must not be empty.");
        this.id = id;
        this.typeInfo = Preconditions.checkNotNull(typeInfo, "TypeInformation cannot be null.");

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Make the OutputTag an anonymous inner class: add '{}' — new OutputTag<Tuple2<String, Long>>("side"){}.
  2. Or pass TypeInformation explicitly: new OutputTag<>("side", Types.TUPLE(Types.STRING, Types.LONG)).
  3. Never declare OutputTag fields with an unbound generic variable; instantiate at a concrete type.
  4. In Kotlin use 'object : OutputTag<...>("id") {}'.

Example fix

// before
OutputTag<Tuple2<String, Long>> tag = new OutputTag<Tuple2<String, Long>>("side"); // no {}

// after
OutputTag<Tuple2<String, Long>> tag = new OutputTag<Tuple2<String, Long>>("side") {};
// or explicit:
OutputTag<Tuple2<String, Long>> tag2 = new OutputTag<>("side", Types.TUPLE(Types.STRING, Types.LONG));
Defensive patterns

Strategy: type-guard

Validate before calling

static <T> OutputTag<T> outputTag(String id, TypeInformation<T> ti) {
    return new OutputTag<>(id, ti); // explicit TypeInformation never fails extraction
}

Type guard

// compile-time-safe pattern: anonymous subclass fixes the type parameter
new OutputTag<Tuple2<String, Long>>("side") {}

Try / catch

try { new OutputTag<...>(id); } catch (InvalidTypesException e) { /* fall back to explicit TypeInformation overload */ } — better: always use the (id, TypeInformation) constructor in shared/generic code.

Prevention

When it happens

Trigger: new OutputTag<Tuple2<String, Long>>("id") without the trailing {}; using OutputTag<T> inside a generic function/method where T is erased; serializing an OutputTag subclass with a wildcard or type-variable parameter.

Common situations: Side outputs in process function code first written without '{}'; reusable OutputTags in generic base classes; Kotlin/Scala code dropping the anonymous-subclass trick (Kotlin: object : OutputTag<Tuple2<String, Long>>("id") {}).

Related errors


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/3dd4dd34da9939bf. Report an issue: GitHub.