{"record":{"id":"e08ba68de356a08d","repo":"XTLS/Xray-core","slug":"read-remaining-bytes-w","errorCode":null,"errorMessage":"read remaining bytes: %w","messagePattern":"read remaining bytes: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"transport/internet/finalmask/xmc/protocol.go","lineNumber":340,"sourceCode":"\n\tbuf := make([]byte, length)\n\n\t_, err = io.ReadFull(r, buf)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read bytes: %w\", err)\n\t}\n\n\t*v = append([]byte(*v), buf...)\n\n\treturn nil\n}\n\ntype RestBytes []byte\n\nfunc (v *RestBytes) readFrom(r io.Reader) error {\n\tbuf, err := io.ReadAll(r)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read remaining bytes: %w\", err)\n\t}\n\t*v = append((*v)[:0], buf...)\n\treturn nil\n}\n\nfunc (v *RestBytes) writeTo(w io.Writer) error {\n\tif _, err := w.Write(*v); err != nil {\n\t\treturn fmt.Errorf(\"write remaining bytes: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (v *Bytes) writeTo(w io.Writer) error {\n\tlength := Varint(len(*v))\n\terr := length.writeTo(w)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"write bytes length: %w\", err)\n\t}","sourceCodeStart":322,"sourceCodeEnd":358,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/transport/internet/finalmask/xmc/protocol.go#L322-L358","documentation":"RestBytes.readFrom slurps everything remaining on the stream with io.ReadAll and wraps any failure with this message. RestBytes is the trailing 'rest of packet' field, so this error means the connection failed while draining the remainder of a frame — typically the peer disconnecting mid-read or a read deadline firing.","triggerScenarios":"Reading a packet whose last field is RestBytes when the connection resets or EOFs before the reader finishes; ReadAll hitting a deadlines error on a Conn.","commonSituations":"Server closes the connection right after sending a partial final packet; long-lived connection killed by NAT idle timeout while a large trailing field was in flight.","solutions":["Distinguish clean EOF (peer closed gracefully — often normal at end of session) from ErrUnexpectedEOF/reset (failure).","Set read deadlines and refresh them per packet to avoid indefinite blocking then abrupt timeout errors.","Reconnect/retry at the session layer if the protocol supports resumption.","Log the packet ID being parsed when the error occurs to identify the phase."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := rest.readFrom(r); err != nil {\n    if errors.Is(err, io.EOF) {\n        return nil // graceful close at boundary during drain is normal\n    }\n    return fmt.Errorf(\"failed draining packet tail: %w\", err)\n}","preventionTips":["Refresh read deadlines after each packet to survive NAT idle timeouts.","Distinguish graceful EOF from truncation before alerting.","Log the packet being parsed when the drain fails."],"tags":["go","network","io","protocol-framing"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}