{"record":{"id":"77c2e7f5d9697c91","repo":"alibaba/canal","slug":"eof-encountered","errorCode":null,"errorMessage":"EOF encountered.","messagePattern":"EOF encountered\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/BioSocketChannel.java","lineNumber":60,"sourceCode":"        } else {\n            throw new SocketException(\"Socket already closed.\");\n        }\n    }\n\n    public byte[] read(int readSize) throws IOException {\n        InputStream input = this.input;\n        byte[] data = new byte[readSize];\n        int remain = readSize;\n        if (input == null) {\n            throw new SocketException(\"Socket already closed.\");\n        }\n        while (remain > 0) {\n            try {\n                int read = input.read(data, readSize - remain, remain);\n                if (read > -1) {\n                    remain -= read;\n                } else {\n                    throw new IOException(\"EOF encountered.\");\n                }\n            } catch (SocketTimeoutException te) {\n                if (Thread.interrupted()) {\n                    throw new ClosedByInterruptException();\n                }\n            }\n        }\n        return data;\n    }\n\n    public byte[] read(int readSize, int timeout) throws IOException {\n        InputStream input = this.input;\n        byte[] data = new byte[readSize];\n        int remain = readSize;\n        int accTimeout = 0;\n        if (input == null) {\n            throw new SocketException(\"Socket already closed.\");\n        }","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/BioSocketChannel.java#L42-L78","documentation":"Thrown by BioSocketChannel.read(int) when the underlying InputStream.read returns -1, meaning the peer (MySQL server) closed its side of the TCP connection before the requested bytes arrived. This is a genuine end-of-stream on the socket, not a timeout. The read loop treats read == -1 as a hard EOF.","triggerScenarios":"MySQL server closed the connection (normal quit, server shutdown, KILL of the binlog dump thread), a network device/intermediary severed the link, or the server sent an error packet and dropped the connection mid-read.","commonSituations":"Long-lived binlog dump connection dropped by a server idle timeout, wait_timeout, or a load balancer; MySQL restart; the binlog client requested an invalid position and the server closed after sending an error; firewall/NAT reaping idle connections.","solutions":["Treat EOF as a trigger to reconnect from the last recorded binlog position (GTID/file+pos).","Increase server-side wait_timeout / interactive_timeout and keep the connection active with periodic pings.","Enable TCP keepalive (setKeepAlive is already true) and tune keepalive intervals for NAT environments.","Inspect the server error log and any error packet received just before EOF to find the root cause.","Wrap the read in retry logic bounded by a backoff policy."],"exampleFix":"// before\nbyte[] body = channel.read(bodyLen); // EOF -> IOException\n\n// after\ntry {\n    byte[] body = channel.read(bodyLen);\n} catch (IOException eof) {\n    if (eof.getMessage().contains(\"EOF\")) {\n        reconnectFromLastPosition();\n        return;\n    }\n    throw eof;\n}","handlingStrategy":"retry","validationCode":"// EOF cannot be pre-validated without reading; pre-check only open state\nif (channel == null || !channel.isConnected()) { reconnectFromLastPosition(); }","typeGuard":null,"tryCatchPattern":"try {\n    byte[] body = channel.read(bodyLen);\n} catch (java.io.IOException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"EOF\")) {\n        reconnectFromLastPosition();\n    } else throw e;\n}","preventionTips":["Persist the last binlog position so EOF triggers a clean reconnect-and-resume.","Send periodic heartbeats/PINGs to keep the connection alive.","Tune wait_timeout and TCP keepalive for the network environment."],"tags":["network","socket","io","eof","disconnection"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}