{"record":{"id":"a432ec2fb22f57db","repo":"dotnet/aspnetcore","slug":"invalid-payload-for-completion-message-a432ec","errorCode":null,"errorMessage":"Invalid payload for Completion message.","messagePattern":"Invalid payload for Completion message\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/SignalR/clients/ts/signalr/src/JsonHubProtocol.ts","lineNumber":111,"sourceCode":"    private _isInvocationMessage(message: InvocationMessage): void {\n        this._assertNotEmptyString(message.target, \"Invalid payload for Invocation message.\");\n\n        if (message.invocationId !== undefined) {\n            this._assertNotEmptyString(message.invocationId, \"Invalid payload for Invocation message.\");\n        }\n    }\n\n    private _isStreamItemMessage(message: StreamItemMessage): void {\n        this._assertNotEmptyString(message.invocationId, \"Invalid payload for StreamItem message.\");\n\n        if (message.item === undefined) {\n            throw new Error(\"Invalid payload for StreamItem message.\");\n        }\n    }\n\n    private _isCompletionMessage(message: CompletionMessage): void {\n        if (message.result && message.error) {\n            throw new Error(\"Invalid payload for Completion message.\");\n        }\n\n        if (!message.result && message.error) {\n            this._assertNotEmptyString(message.error, \"Invalid payload for Completion message.\");\n        }\n\n        this._assertNotEmptyString(message.invocationId, \"Invalid payload for Completion message.\");\n    }\n\n    private _isAckMessage(message: AckMessage): void {\n        if (typeof message.sequenceId !== 'number') {\n            throw new Error(\"Invalid SequenceId for Ack message.\");\n        }\n    }\n\n    private _isSequenceMessage(message: SequenceMessage): void {\n        if (typeof message.sequenceId !== 'number') {\n            throw new Error(\"Invalid SequenceId for Sequence message.\");","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/SignalR/clients/ts/signalr/src/JsonHubProtocol.ts#L93-L129","documentation":"A Completion message (type 3) is the terminal result of an invocation and the protocol forbids it from carrying both `result` and `error` at once. The invariant is: zero or one of them, never both, mirroring the IHubProtocol.ts CompletionMessage contract.","triggerScenarios":"Server sends {\"type\":3,\"invocationId\":\"x\",\"result\":...,\"error\":\"boom\"}. This is a server-side bug or a custom hub/protocol implementation that sets both fields.","commonSituations":"A custom server hub that populates both fields, an older server with a serialization bug, or a buggy intermediate that injects an error string while preserving a result.","solutions":["Fix the server to set either result or error on completion, never both.","Capture the raw wire message with logMessageContent:true to confirm both fields are present.","Upgrade the server SignalR package to a version where the completion invariant is enforced server-side.","If testing a custom protocol, validate the message shape before sending."],"exampleFix":"// before\n{ \"type\": 3, \"invocationId\": \"x\", \"result\": 42, \"error\": \"oops\" }\n\n// after\n{ \"type\": 3, \"invocationId\": \"x\", \"result\": 42 }","handlingStrategy":"validation","validationCode":"// when constructing/sending a completion\nfunction buildCompletion(invocationId: string, result?: any, error?: string) {\n  if (result !== undefined && error) {\n    throw new Error('result and error are mutually exclusive');\n  }\n  return { type: 3, invocationId, result, error };\n}","typeGuard":"function isValidCompletion(m: any): boolean {\n  return !(m?.result && m?.error);\n}","tryCatchPattern":null,"preventionTips":["Treat result and error as mutually exclusive in any completion builder.","Upgrade the server SignalR package so it enforces the invariant server-side.","In tests, assert completions carry at most one of result/error."],"tags":["typescript","signalr","protocol","validation","message-invariant"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}