{"record":{"id":"a6b34548830d5063","repo":"apache/flink","slug":"nofetchinginput-cannot-prefetch-data","errorCode":null,"errorMessage":"NoFetchingInput cannot prefetch data.","messagePattern":"NoFetchingInput cannot prefetch data\\.","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"flink-core/src/main/java/org/apache/flink/api/java/typeutils/runtime/NoFetchingInput.java","lineNumber":45,"sourceCode":"import java.io.EOFException;\nimport java.io.IOException;\nimport java.io.InputStream;\n\n@Internal\npublic class NoFetchingInput extends Input {\n    public NoFetchingInput(InputStream inputStream) {\n        super(inputStream, 8);\n    }\n\n    @Override\n    public int read() throws KryoException {\n        require(1);\n        return buffer[position++] & 0xFF;\n    }\n\n    @Override\n    public boolean canReadInt() throws KryoException {\n        throw new UnsupportedOperationException(\"NoFetchingInput cannot prefetch data.\");\n    }\n\n    @Override\n    public boolean canReadLong() throws KryoException {\n        throw new UnsupportedOperationException(\"NoFetchingInput cannot prefetch data.\");\n    }\n\n    /**\n     * Require makes sure that at least required number of bytes are kept in the buffer. If not,\n     * then it will load exactly the difference between required and currently available number of\n     * bytes. Thus, it will only load the data which is required and never prefetch data.\n     *\n     * @param required the number of bytes being available in the buffer\n     * @return The number of bytes remaining in the buffer, which will be at least <code>required\n     *     </code> bytes.\n     * @throws KryoException\n     */\n    @Override","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-core/src/main/java/org/apache/flink/api/java/typeutils/runtime/NoFetchingInput.java#L27-L63","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Remove the custom ClassResolver or rewrite it so it does not call canReadInt()","Replace canReadInt()-based optional-field logic in custom serializers with explicit version bytes you write/read yourself","Test the full serialization round-trip under Flink's NoFetchingInput, not just plain Kryo Input"],"exampleFix":"// before (custom serializer)\nif (input.canReadInt()) {\n    obj.setOptional(input.readInt());\n}\n\n// after (explicit flag)\nboolean hasOptional = input.readByte() == 1;\nif (hasOptional) {\n    obj.setOptional(input.readInt());\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    kryo.readObject(input, type);\n} catch (UnsupportedOperationException e) {\n    if (e.getMessage().contains(\"NoFetchingInput\")) {\n        throw new IllegalStateException(\"Custom Kryo code uses canReadInt(); not supported under Flink runtime\", e);\n    }\n    throw e;\n}","preventionTips":["Never call canReadInt()/canReadLong() in custom Serializers or ClassResolvers used with Flink","Encode optional data with explicit flags instead of stream probing","Test custom Kryo serializers inside a Flink job, not only standalone Kryo"],"tags":["kryo","serialization","streaming-input","unsupported-operation"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}