{"record":{"id":"a8abe234da77e782","repo":"alibaba/canal","slug":"end-of-stream-when-reading-header","errorCode":null,"errorMessage":"end of stream when reading header","messagePattern":"end of stream when reading header","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/connector/SimpleAdminConnector.java","lineNumber":309,"sourceCode":"        writeHeader.flip();\n        channel.write(writeHeader);\n        channel.write(ByteBuffer.wrap(body));\n    }\n\n    private byte[] readNextPacket(ReadableByteChannel channel) throws IOException {\n        readHeader.clear();\n        read(channel, readHeader);\n        int bodyLen = readHeader.getInt(0);\n        ByteBuffer bodyBuf = ByteBuffer.allocate(bodyLen).order(ByteOrder.BIG_ENDIAN);\n        read(channel, bodyBuf);\n        return bodyBuf.array();\n    }\n\n    private void read(ReadableByteChannel channel, ByteBuffer buffer) throws IOException {\n        while (buffer.hasRemaining()) {\n            int r = channel.read(buffer);\n            if (r == -1) {\n                throw new IOException(\"end of stream when reading header\");\n            }\n        }\n    }\n\n    private void quietlyClose(Channel channel) {\n        try {\n            channel.close();\n        } catch (IOException e) {\n            logger.warn(\"exception on closing channel:{} \\n {}\", channel, e);\n        }\n    }\n}\n","sourceCodeStart":291,"sourceCodeEnd":322,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/admin/admin-web/src/main/java/com/alibaba/otter/canal/admin/connector/SimpleAdminConnector.java#L291-L322","documentation":"Thrown by the read() helper when channel.read() returns -1, meaning the remote end closed the connection before the full header buffer was filled. The connector treats truncated reads as fatal.","triggerScenarios":"Any readNextPacket() call where the canal-server closes/resets the socket mid-packet (during handshake, auth, or an admin operation), so the 4-byte header read loop hits EOF.","commonSituations":"Server crash or restart mid-operation; network interruption; server-side timeout closing idle connections; firewall/proxy dropping the long-lived admin socket; the soTimeout elapsed and the socket was torn down.","solutions":["Check that the canal-server is running and reachable (telnet/ping the admin port).","Increase soTimeout if the idle timeout is closing the socket before operations complete.","Reconnect (the connector resets on disconnect) and retry the operation idempotently.","Inspect server logs for crashes/OOM/abrupt shutdowns coinciding with the disconnect."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    connector.doX();\n} catch (ServiceException e) {\n    if (e.getCause() instanceof IOException && e.getCause().getMessage().contains(\"end of stream\")) {\n        // server closed socket; reconnect and retry idempotent op once\n    }\n    throw e;\n}","preventionTips":["Monitor canal-server health; reconnect on EOF.","Tune soTimeout to exceed the longest expected operation.","Make admin operations idempotent so a reconnect+retry is safe."],"tags":["network","connection-reset","io","canal-admin"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}