{"record":{"id":"9c46a3cdebaa3123","repo":"signalapp/Signal-Server","slug":"invalid-argument","errorCode":"INVALID_ARGUMENT","errorMessage":"extension requires a value to be set","messagePattern":"extension requires a value to be set","errorType":"validation","errorClass":"StatusRuntimeException","httpStatus":null,"severity":"warning","filePath":"service/src/main/java/org/whispersystems/textsecuregcm/grpc/ValidatingInterceptor.java","lineNumber":141,"sourceCode":"        // Checking for repeated fields also handles maps, because maps are syntax sugar for repeated MapEntries\n        // which themselves are Messages that will be recursively descended.\n        for (final Object o : list) {\n          validateMessage(o);\n        }\n      } else if (fd.hasPresence() && msg.hasField(fd)) {\n        // If the field has presence information and is present, recursively validate it. Not all fields have\n        // presence, but we only validate Message type fields anyway, which always have explicit presence.\n        validateMessage(msg.getField(fd));\n      }\n    }\n  }\n\n  private void validateField(final FieldValidator<?> validator, final Object extensionValue, final Message msg, final Descriptors.FieldDescriptor fd) {\n    // for the fields with an `optional` modifier, checking if the field was set\n    // and if not, checking if extension allows missing optional field\n    if (fd.hasPresence() && !msg.hasField(fd)) {\n      switch (validator.getMissingOptionalAction()) {\n        case FAIL -> throw fieldViolation(fd, validator.getExtensionName(), \"extension requires a value to be set\");\n        case SUCCEED -> {\n          return;\n        }\n        case VALIDATE_DEFAULT_VALUE -> {}\n      }\n    }\n\n    try {\n      validator.validate(extensionValue, fd, msg.getField(fd));\n    } catch (FieldValidationException e) {\n      throw fieldViolation(fd, validator.getExtensionName(), e.getMessage());\n    }\n  }\n\n  private void validateRepeatedElementConstraints(\n      final ElementConstraint elementConstraint,\n      final Message message,\n      final Descriptors.FieldDescriptor fd) {","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/signalapp/Signal-Server/blob/100ab61c82627582c867d19e1c0561ba2781e927/service/src/main/java/org/whispersystems/textsecuregcm/grpc/ValidatingInterceptor.java#L123-L159","documentation":"The gRPC ValidatingInterceptor validates incoming protobuf messages against declarative field validators (extensions). For proto3 fields with explicit presence (optional), when a field is unset and the attached validator extension requires a value (getMissingOptionalAction() == FAIL), the interceptor rejects the request with INVALID_ARGUMENT and the message 'extension requires a value to be set'.","triggerScenarios":"A gRPC client sends a request message where an `optional` field with a presence-requiring validator extension is left unset — e.g. omitting a required-by-policy field in a request proto while the server's validation extension sets missing_optional action to FAIL.","commonSituations":"Client SDKs generated from older protos that don't set the newly added optional field; clients constructing requests programmatically and skipping a field assumed optional; proto schema drift between client and server.","solutions":["Set the flagged field explicitly in the client request — the error identifies the field/extension via the field violation detail.","Regenerate client stubs from the current proto definitions so all validated fields are known and populated.","If the field genuinely should be optional, change the validator extension's missingOptional action to SUCCEED (or VALIDATE_DEFAULT_VALUE) server-side.","Run client-side validation with the same validator definitions before sending to catch violations early."],"exampleFix":"// before: optional validated field left unset\nMyRequest.newBuilder().setOtherField(\"x\").build();\n\n// after: always set presence-tracked validated fields\nMyRequest.newBuilder()\n    .setOtherField(\"x\")\n    .setRequiredByValidator(\"value\") // field with missing_optional=FAIL extension\n    .build();","handlingStrategy":"validation","validationCode":"// client-side, before sending\nMyRequest req = MyRequest.newBuilder()...build();\nfor (var fd : req.getDescriptorForType().getFields()) {\n  if (fd.hasPresence() && !req.hasField(fd)) {\n    throw new IllegalArgumentException(\"Field with presence must be set: \" + fd.getName());\n  }\n}","typeGuard":"boolean isFieldSet(com.google.protobuf.Message msg, Descriptors.FieldDescriptor fd) {\n  return !fd.hasPresence() || msg.hasField(fd);\n}","tryCatchPattern":"try {\n  stub.call(request);\n} catch (StatusRuntimeException e) {\n  if (e.getStatus().getCode() == Status.Code.INVALID_ARGUMENT) {\n    // inspect trailers for fieldViolation naming the unset field and populate it\n  }\n}","preventionTips":["Regenerate client stubs whenever server protos add optional-but-validated fields.","Share validator extension definitions between client and server so requirements are visible to both.","Add integration tests that send fully-populated requests for each RPC."],"tags":["grpc","protobuf","validation","invalid-argument"],"backgroundTag":"missing-required-argument","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"}