{"record":{"id":"0e7682cf5932e538","repo":"dotnet/aspnetcore","slug":"message-is-incomplete-0e7682","errorCode":null,"errorMessage":"Message is incomplete.","messagePattern":"Message is incomplete\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/GsonHubProtocol.java","lineNumber":60,"sourceCode":"\n    @Override\n    public List<HubMessage> parseMessages(ByteBuffer payload, InvocationBinder binder) {\n        String payloadStr;\n        // If the payload is readOnly, we have to copy the bytes from its array to make the payload string\n        if (payload.isReadOnly()) {\n            byte[] payloadBytes = new byte[payload.remaining()];\n            payload.get(payloadBytes, 0, payloadBytes.length);\n            payloadStr = new String(payloadBytes, StandardCharsets.UTF_8);\n        // Otherwise we can allocate directly from its array\n        } else {\n            // The position of the ByteBuffer may have been incremented - make sure we only grab the remaining bytes\n            payloadStr = new String(payload.array(), payload.position(), payload.remaining(), StandardCharsets.UTF_8);\n        }\n        if (payloadStr.length() == 0) {\n            return null;\n        }\n        if (!(payloadStr.substring(payloadStr.length() - 1).equals(RECORD_SEPARATOR))) {\n            throw new RuntimeException(\"Message is incomplete.\");\n        }\n\n        String[] messages = payloadStr.split(RECORD_SEPARATOR);\n        List<HubMessage> hubMessages = new ArrayList<>();\n        try {\n            for (String str : messages) {\n                HubMessageType messageType = null;\n                String invocationId = null;\n                String target = null;\n                String error = null;\n                ArrayList<Object> arguments = null;\n                JsonArray argumentsToken = null;\n                Object result = null;\n                Exception argumentBindingException = null;\n                JsonElement resultToken = null;\n                JsonReader reader = new JsonReader(new StringReader(str));\n                reader.beginObject();\n","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/GsonHubProtocol.java#L42-L78","documentation":"GsonHubProtocol splits the ByteBuffer on the Record Separator (\\u001e). If the payload's last character is not that separator, the framing is treated as truncated and the parse is rejected before attempting JSON parsing, mirroring the TypeScript TextMessageFormat behavior.","triggerScenarios":"A truncated/partial ByteBuffer, a custom transport that does not append the separator, or message reassembly that drops the trailing byte before reaching the parser.","commonSituations":"Partial network reads not fully buffered, a buggy custom transport, proxy body truncation, or test fixtures that omit the separator.","solutions":["Buffer the full framed payload (including the trailing 0x1e) before calling parseMessages.","Ensure custom transports append RECORD_SEPARATOR on write and preserve framing on read.","Check for proxies/CDNs truncating the response body.","Log the raw payload bytes to confirm the trailing separator."],"exampleFix":"// before\nString payload = \"{...json...}\"; // missing separator\n\n// after\nString payload = \"{...json...}\" + \"\\u001e\";","handlingStrategy":"try-catch","validationCode":"boolean isFullyFramed(String payload) {\n  return payload != null && payload.length() > 0\n    && payload.substring(payload.length() - 1).equals(\"\\u001e\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  protocol.parseMessages(buffer, binder);\n} catch (RuntimeException e) {\n  if (\"Message is incomplete.\".equals(e.getMessage())) {\n    // re-buffer until the record separator is present\n  }\n}","preventionTips":["Fully buffer framed records (trailing 0x1e) before parsing.","Custom transports must append the record separator on write.","Validate payloads in tests with the separator included."],"tags":["java","signalr","protocol","message-framing","transport"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}