dotnet/aspnetcore · error · RuntimeException

Error reading JSON.

Error message

Error reading JSON.

What it means

GsonHubProtocol streams through the JSON with a JsonReader; any IOException (truncated token, unexpected end, malformed value) thrown during the parse loop is caught and rethrown as a RuntimeException with this message. It signals genuinely malformed JSON in a framed record.

Source

Thrown at src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/GsonHubProtocol.java:220

                    case STREAM_INVOCATION:
                    case CANCEL_INVOCATION:
                        throw new UnsupportedOperationException(String.format("The message type %s is not supported yet.", messageType));
                    case PING:
                        hubMessages.add(PingMessage.getInstance());
                        break;
                    case CLOSE:
                        if (error != null) {
                            hubMessages.add(new CloseMessage(error));
                        } else {
                            hubMessages.add(new CloseMessage());
                        }
                        break;
                    default:
                        break;
                }
            }
        } catch (IOException ex) {
            throw new RuntimeException("Error reading JSON.", ex);
        }

        return hubMessages;
    }

    @Override
    public ByteBuffer writeMessage(HubMessage hubMessage) {
        return ByteBuffer.wrap((gson.toJson(hubMessage) + RECORD_SEPARATOR).getBytes(StandardCharsets.UTF_8));
    }

    private ArrayList<Object> bindArguments(JsonArray argumentsToken, List<Type> paramTypes) {
        if (argumentsToken.size() != paramTypes.size()) {
            throw new RuntimeException(String.format("Invocation provides %d argument(s) but target expects %d.", argumentsToken.size(), paramTypes.size()));
        }

        ArrayList<Object> arguments = null;
        if (paramTypes.size() >= 1) {
            arguments = new ArrayList<>();

View on GitHub (pinned to 294cab2f9b)

Solutions

  1. Capture the raw record bytes (enable message-content logging) and validate them with an external JSON parser.
  2. Confirm the transport delivers UTF-8 without re-encoding by intermediaries.
  3. Upgrade the server SignalR/serializer to rule out serialization bugs.
  4. If intermittent, suspect packet corruption or a proxy mangling the body.

Example fix

// diagnostics: log the offending record before parsing
for (String rec : payloadStr.split(RECORD_SEPARATOR)) {
  try { new JsonParser().parse(rec); }
  catch (Exception ex) { System.err.println("Bad record: " + rec); }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-validate each framed record with a lenient parser before handing to the protocol
for (String rec : payload.split("\u001e")) {
  try { JsonParser.parseString(rec); }
  catch (Exception ex) { /* log offending record */ }
}

Try / catch

try {
  protocol.parseMessages(buffer, binder);
} catch (RuntimeException e) {
  if ("Error reading JSON.".equals(e.getMessage()) && e.getCause() != null) {
    // e.getCause() is the original IOException with parse location
  }
}

Prevention

When it happens

Trigger: A record that passed the record-separator framing check but contains invalid JSON: premature end of object, bad token, mismatched braces, or a number where a string is expected by the reader.

Common situations: Network corruption that leaves framing intact but breaks JSON, a buggy server serializer, a partial record that happens to end in 0x1e, or charset/encoding issues (non-UTF8 bytes).

Related errors


AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06). Data as JSON: /api/errors/be0185afdba64d12. Report an issue: GitHub.