apache/flink · error · UnsupportedOperationException

NoFetchingInput cannot prefetch data.

Error message

NoFetchingInput cannot prefetch data.

What it means

NoFetchingInput deliberately overrides canReadInt() to throw UnsupportedOperationException. This InputStream adapter only loads exactly the bytes a read requires (never prefetching), but Kryo's canReadInt() would have to look ahead at the next class-id byte, which is impossible without consuming it.

Source

Thrown at flink-core/src/main/java/org/apache/flink/api/java/typeutils/runtime/NoFetchingInput.java:45

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;

@Internal
public class NoFetchingInput extends Input {
    public NoFetchingInput(InputStream inputStream) {
        super(inputStream, 8);
    }

    @Override
    public int read() throws KryoException {
        require(1);
        return buffer[position++] & 0xFF;
    }

    @Override
    public boolean canReadInt() throws KryoException {
        throw new UnsupportedOperationException("NoFetchingInput cannot prefetch data.");
    }

    @Override
    public boolean canReadLong() throws KryoException {
        throw new UnsupportedOperationException("NoFetchingInput cannot prefetch data.");
    }

    /**
     * Require makes sure that at least required number of bytes are kept in the buffer. If not,
     * then it will load exactly the difference between required and currently available number of
     * bytes. Thus, it will only load the data which is required and never prefetch data.
     *
     * @param required the number of bytes being available in the buffer
     * @return The number of bytes remaining in the buffer, which will be at least <code>required
     *     </code> bytes.
     * @throws KryoException
     */
    @Override

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Remove the custom ClassResolver or rewrite it so it does not call canReadInt()
  2. Replace canReadInt()-based optional-field logic in custom serializers with explicit version bytes you write/read yourself
  3. Test the full serialization round-trip under Flink's NoFetchingInput, not just plain Kryo Input

Example fix

// before (custom serializer)
if (input.canReadInt()) {
    obj.setOptional(input.readInt());
}

// after (explicit flag)
boolean hasOptional = input.readByte() == 1;
if (hasOptional) {
    obj.setOptional(input.readInt());
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
    kryo.readObject(input, type);
} catch (UnsupportedOperationException e) {
    if (e.getMessage().contains("NoFetchingInput")) {
        throw new IllegalStateException("Custom Kryo code uses canReadInt(); not supported under Flink runtime", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: A Kryo ClassResolver or Serializer implementation calls input.canReadInt() while deserializing through Flink's DataInputView-based KryoDeserializer paths - e.g. custom ClassResolver implementations (like certain version-resolving resolvers) or serializers that peek the next registration id.

Common situations: User registers a custom Kryo ClassResolver (kryo.setClassResolver(...)) that uses canReadInt() to detect optional trailing class ids; upgrading Kryo version changes internal call patterns; custom serializers copied from Kryo examples that call canReadInt/canReadLong for optional fields.

Related errors


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