{"record":{"id":"48636df05c0d5089","repo":"dotnet/aspnetcore","slug":"expected-either-error-or-result-to-be-provided","errorCode":null,"errorMessage":"Expected either 'error' or 'result' to be provided, but not both.","messagePattern":"Expected either 'error' or 'result' to be provided, but not both\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/CompletionMessage.java","lineNumber":20,"sourceCode":"// The .NET Foundation licenses this file to you under the MIT license.\n\npackage com.microsoft.signalr;\n\nimport java.util.Map;\n\npublic final class CompletionMessage extends HubMessage {\n    private final int type = HubMessageType.COMPLETION.value;\n    private Map<String, String> headers;\n    private final String invocationId;\n    private final Object result;\n    private final String error;\n\n    public CompletionMessage(Map<String, String> headers, String invocationId, Object result, String error) {\n        if (headers != null && !headers.isEmpty()) {\n            this.headers = headers;\n        }\n        if (error != null && result != null) {\n            throw new IllegalArgumentException(\"Expected either 'error' or 'result' to be provided, but not both.\");\n        }\n        this.invocationId = invocationId;\n        this.result = result;\n        this.error = error;\n    }\n\n    public Map<String, String> getHeaders() {\n        return headers;\n    }\n\n    public Object getResult() {\n        return result;\n    }\n\n    public String getError() {\n        return error;\n    }\n","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/CompletionMessage.java#L2-L38","documentation":"CompletionMessage's constructor enforces the hub protocol invariant that a completion carries either an error or a result, but never both. Passing both non-null is contradictory (success vs failure) and would violate the wire contract.","triggerScenarios":"Constructing CompletionMessage manually with both error and result non-null, typically in tests, custom protocol layers, or hand-built message factories.","commonSituations":"Unit tests building fixtures incorrectly, a custom hub/protocol wrapper that sets both fields, or copy-paste leaving a stale error alongside a result.","solutions":["Pass exactly one of result or error; leave the other null.","Centralize CompletionMessage construction in a factory that enforces the invariant.","Add an assertion in your builder so both-non-null fails earlier with a clearer message.","If you need to represent 'result with warning', put the warning elsewhere (e.g. headers), not in error."],"exampleFix":"// before\nnew CompletionMessage(null, invocationId, result, \"warn\"); // both set\n\n// after\nnew CompletionMessage(null, invocationId, result, null);","handlingStrategy":"validation","validationCode":"static CompletionMessage build(String id, Object result, String error) {\n  if (result != null && error != null) {\n    throw new IllegalArgumentException(\"Provide result OR error, not both\");\n  }\n  return new CompletionMessage(null, id, result, error);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use a single factory for CompletionMessage that enforces the invariant.","In tests, never set both result and error.","Route warnings through headers instead of the error field."],"tags":["java","signalr","protocol","validation","message-invariant"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}