apache/flink · error · InvalidSemanticAnnotationException

Target field {} was added twice.

Error message

Target field {} was added twice.

What it means

Thrown by SingleInputSemanticProperties.addForwardedField(int sourceField, int targetField) when the targetField position has already been registered as a forwarded target from any source field. The method enforces that each output field is forwarded from exactly one input field; a second mapping to the same target is a contradictory semantic annotation.

Source

Thrown at flink-core/src/main/java/org/apache/flink/api/common/operators/SingleInputSemanticProperties.java:86

    @Override
    public FieldSet getReadFields(int input) {
        if (input != 0) {
            throw new IndexOutOfBoundsException();
        }

        return this.readFields;
    }

    /**
     * Adds, to the existing information, a field that is forwarded directly from the source
     * record(s) to the destination record(s).
     *
     * @param sourceField the position in the source record(s)
     * @param targetField the position in the destination record(s)
     */
    public void addForwardedField(int sourceField, int targetField) {
        if (isTargetFieldPresent(targetField)) {
            throw new InvalidSemanticAnnotationException(
                    "Target field " + targetField + " was added twice.");
        }

        FieldSet targetFields = fieldMapping.get(sourceField);
        if (targetFields != null) {
            fieldMapping.put(sourceField, targetFields.addField(targetField));
        } else {
            fieldMapping.put(sourceField, new FieldSet(targetField));
        }
    }

    private boolean isTargetFieldPresent(int targetField) {
        for (FieldSet targetFields : fieldMapping.values()) {
            if (targetFields.contains(targetField)) {
                return true;
            }
        }
        return false;

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Review the function's @ForwardedField annotations and ensure each target field index appears in exactly one annotation.
  2. If a field is genuinely computed (not forwarded), remove it from @ForwardedField annotations.
  3. If you are manually building SingleInputSemanticProperties, check isTargetFieldPresent(targetField) before calling addForwardedField, or audit the fieldMapping for duplicate targets.
  4. Use @ForwardedFields with correct source->target position expressions.

Example fix

// before
@ForwardedField("0->1; 2->1") // ERROR: target field 1 twice
public static class MyMapper extends RichMapFunction<Tuple3<String, Integer, String>, Tuple2<String, Integer>> {
    public Tuple2<String, Integer> map(Tuple3<String, Integer, String> in) { ... }
}

// after
@ForwardedField("0->1")
public static class MyMapper extends RichMapFunction<Tuple3<String, Integer, String>, Tuple2<String, Integer>> {
    public Tuple2<String, Integer> map(Tuple3<String, Integer, String> in) { ... }
}
Defensive patterns

Strategy: validation

Validate before calling

void safeAddForwardedField(SingleInputSemanticProperties props, int source, int target) {
    if (props instanceof SingleInputSemanticProperties.AllFieldsForwardedProperties) return;
    // Check if target is already claimed by another source
    for (int s = 0; s < 256; s++) {
        if (s != source && props.getForwardingTargetFields(0, s).contains(target)) {
            throw new IllegalStateException("Target field " + target + " already forwarded from source " + s);
        }
    }
    props.addForwardedField(source, target);
}

Type guard

boolean isTargetAvailable(SingleInputSemanticProperties props, int targetField) {
    return props.getForwardingSourceField(0, targetField) == -1;
}

Try / catch

try {
    props.addForwardedField(sourceField, targetField);
} catch (InvalidSemanticAnnotationException e) {
    // duplicate target field annotation; review @ForwardedField annotations
    throw new RuntimeException("Duplicate @ForwardedField target: " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: Manually calling addForwardedField(0, 1) followed by addForwardedField(2, 1) on the same SingleInputSemanticProperties instance. Using duplicate or overlapping @ForwardedField annotations on a function that the compiler translates into addForwardedField calls.

Common situations: Incorrect @ForwardedField annotations on a MapFunction or FlatMapFunction where two input fields are annotated as forwarding to the same output position. Copy-paste errors when annotating a rich function's semantic properties. Misunderstanding positional semantics of forwarded fields.

Related errors


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