{"record":{"id":"5ac806ce7ffb5095","repo":"signalapp/Signal-Server","slug":"invalid-protobuf-entity","errorCode":null,"errorMessage":"Invalid protobuf entity","messagePattern":"Invalid protobuf entity","errorType":"http","errorClass":"WebApplicationException","httpStatus":422,"severity":"error","filePath":"service/src/main/java/org/whispersystems/textsecuregcm/controllers/CallQualitySurveyController.java","lineNumber":70,"sourceCode":"      name = \"Retry-After\",\n      description = \"If present, an positive integer indicating the number of seconds before a subsequent attempt could succeed\"))\n  @RateLimitedByIp(RateLimiters.For.SUBMIT_CALL_QUALITY_SURVEY)\n  public void submitCallQualitySurvey(@Auth final Optional<AuthenticatedDevice> authenticatedDevice,\n      @RequestBody(description = \"A serialized survey response protobuf entity\")\n      @NotNull final byte[] surveyResponse,\n      @HeaderParam(HttpHeaders.USER_AGENT) final String userAgentString,\n      @Context final ContainerRequestContext requestContext) {\n\n    if (authenticatedDevice.isPresent()) {\n      throw new ForbiddenException(\"must not use authenticated connection for call quality survey submissions\");\n    }\n\n    final SubmitCallQualitySurveyRequest submitCallQualitySurveyRequest;\n\n    try {\n      submitCallQualitySurveyRequest = SubmitCallQualitySurveyRequest.parseFrom(surveyResponse);\n    } catch (final InvalidProtocolBufferException e) {\n      throw new WebApplicationException(\"Invalid protobuf entity\", 422);\n    }\n\n    final String remoteAddress = (String) requestContext.getProperty(RemoteAddressFilter.REMOTE_ADDRESS_ATTRIBUTE_NAME);\n\n    try {\n      callQualitySurveyManager.submitCallQualitySurvey(submitCallQualitySurveyRequest, remoteAddress, userAgentString);\n    } catch (final CallQualityInvalidArgumentsException e) {\n      throw new WebApplicationException(e.getMessage(), 422);\n    }\n  }\n}\n","sourceCodeStart":52,"sourceCodeEnd":82,"githubUrl":"https://github.com/signalapp/Signal-Server/blob/100ab61c82627582c867d19e1c0561ba2781e927/service/src/main/java/org/whispersystems/textsecuregcm/controllers/CallQualitySurveyController.java#L52-L82","documentation":"Thrown when the raw request body of the call-quality survey submission endpoint cannot be parsed as a valid serialized survey-response protobuf entity. The client sent bytes that fail protobuf parsing (empty, truncated, or not protobuf at all), so the survey submission is rejected instead of being stored.","triggerScenarios":"POST to the call quality survey endpoint with surveyResponse bytes that are not a valid SubmitCallQualitySurveyRequest encoding — wrong message type, truncated data, or non-protobuf payload.","commonSituations":"Client sending JSON instead of protobuf; serializing the wrong message type; partial body due to truncation or encoding transform (e.g. base64-wrapped).","solutions":["Serialize the body with SubmitCallQualitySurveyRequest.toByteArray() (or equivalent) before sending","Validate the payload client-side with parseFrom in a try/catch to catch issues before upload","Confirm Content-Type and transport are not altering the raw bytes"],"exampleFix":"// before\nbyte[] body = jsonMapper.writeValueAsBytes(survey);\n// after\nSubmitCallQualitySurveyRequest req = buildSurveyRequest(...);\nbyte[] body = req.toByteArray(); // protobuf, validated by round-trip parse","handlingStrategy":"try-catch","validationCode":"try { SubmitCallQualitySurveyRequest.parseFrom(bytes); } catch (InvalidProtocolBufferException e) { throw new IllegalArgumentException(\"survey body is not valid protobuf\"); }","typeGuard":null,"tryCatchPattern":"try { submitSurvey(bytes); } catch (WebApplicationException e) { if (e.getResponse().getStatus() == 422) { revalidateAndReserializeProtobuf(); } }","preventionTips":["Always serialize with toByteArray(), never JSON","Round-trip parse before sending","Confirm Content-Type does not transform the body"],"tags":["http-422","protobuf","serialization","survey"],"backgroundTag":"protobuf-unmarshal-failed","analyzedSha":"100ab61c82627582c867d19e1c0561ba2781e927","analyzedAt":"2026-09-09T13:29:47.883Z","contentChangedAt":"2026-09-09T13:29:47.883Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}