{"record":{"id":"c65b6e9400697642","repo":"dotnet/aspnetcore","slug":"invalid-input-for-json-hub-protocol-expected-a-st","errorCode":null,"errorMessage":"Invalid input for JSON hub protocol. Expected a string.","messagePattern":"Invalid input for JSON hub protocol\\. Expected a string\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/SignalR/clients/ts/signalr/src/JsonHubProtocol.ts","lineNumber":31,"sourceCode":"export class JsonHubProtocol implements IHubProtocol {\n\n    /** @inheritDoc */\n    public readonly name: string = JSON_HUB_PROTOCOL_NAME;\n    /** @inheritDoc */\n    public readonly version: number = 2;\n\n    /** @inheritDoc */\n    public readonly transferFormat: TransferFormat = TransferFormat.Text;\n\n    /** Creates an array of {@link @microsoft/signalr.HubMessage} objects from the specified serialized representation.\n     *\n     * @param {string} input A string containing the serialized representation.\n     * @param {ILogger} logger A logger that will be used to log messages that occur during parsing.\n     */\n    public parseMessages(input: string, logger: ILogger): HubMessage[] {\n        // The interface does allow \"ArrayBuffer\" to be passed in, but this implementation does not. So let's throw a useful error.\n        if (typeof input !== \"string\") {\n            throw new Error(\"Invalid input for JSON hub protocol. Expected a string.\");\n        }\n\n        if (!input) {\n            return [];\n        }\n\n        if (logger === null) {\n            logger = NullLogger.instance;\n        }\n\n        // Parse the messages\n        const messages = TextMessageFormat.parse(input);\n\n        const hubMessages = [];\n        for (const message of messages) {\n            const parsedMessage = JSON.parse(message) as HubMessage;\n            if (typeof parsedMessage.type !== \"number\") {\n                throw new Error(\"Invalid payload.\");","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/SignalR/clients/ts/signalr/src/JsonHubProtocol.ts#L13-L49","documentation":"JsonHubProtocol only operates on TransferFormat.Text, so parseMessages requires a string. Passing an ArrayBuffer (or any non-string) violates the protocol contract: the interface permits ArrayBuffer for binary protocols, but the JSON implementation does not, so it throws an explicit error rather than failing mysteriously inside JSON.parse.","triggerScenarios":"Calling JsonHubProtocol.parseMessages with an ArrayBuffer, or wiring a transport that delivers binary chunks (e.g. a MessagePack-style transport) into a JsonHubProtocol instance. Also triggered by a custom IHubProtocol wrapper that forwards raw bytes.","commonSituations":"Mixing the JSON hub protocol with a binary transfer format by accident, a custom transport that does not decode to string, or upgrading a MessagePack setup and forgetting to swap the protocol object.","solutions":["Ensure the hub protocol matches the transport's transfer format: JsonHubProtocol with Text, MessagePackHubProtocol with Binary.","If you call parseMessages directly, coerce/decode the payload to a string first (e.g. new TextDecoder().decode(buffer)).","Check that you did not accidentally pass an ArrayBuffer through a custom IHubProtocol decorator to the JSON protocol.","Verify HttpConnectionOptions.transport and the negotiated protocol agree on text vs binary."],"exampleFix":"// before\nconst protocol = new JsonHubProtocol();\nprotocol.parseMessages(buffer /* ArrayBuffer */, logger); // throws\n\n// after\nconst text = typeof input === 'string' ? input : new TextDecoder().decode(input);\nprotocol.parseMessages(text, logger);","handlingStrategy":"validation","validationCode":"if (typeof input !== 'string') {\n  throw new TypeError('JsonHubProtocol.parseMessages requires a string; got ' + typeof input);\n}\n// or decode before calling\nconst text = typeof input === 'string' ? input : new TextDecoder().decode(input as ArrayBuffer);","typeGuard":"function isStringPayload(v: unknown): v is string {\n  return typeof v === 'string';\n}","tryCatchPattern":"try {\n  protocol.parseMessages(text, logger);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('Expected a string')) {\n    // wrong protocol/transport pairing\n  }\n  throw e;\n}","preventionTips":["Pair JsonHubProtocol only with TransferFormat.Text transports.","Decode binary buffers to UTF-8 strings before handing them to the JSON protocol.","Add a typeof check in any custom transport/protocol wrapper before delegating."],"tags":["typescript","signalr","protocol","validation","type-mismatch"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}