signalapp/Signal-Server · warning · StatusRuntimeException

INVALID_ARGUMENT

INVALID_ARGUMENT

Error message

extension requires a value to be set

What it means

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'.

Solutions

  1. Set the flagged field explicitly in the client request — the error identifies the field/extension via the field violation detail.
  2. Regenerate client stubs from the current proto definitions so all validated fields are known and populated.
  3. If the field genuinely should be optional, change the validator extension's missingOptional action to SUCCEED (or VALIDATE_DEFAULT_VALUE) server-side.
  4. Run client-side validation with the same validator definitions before sending to catch violations early.

Example fix

// before: optional validated field left unset
MyRequest.newBuilder().setOtherField("x").build();

// after: always set presence-tracked validated fields
MyRequest.newBuilder()
    .setOtherField("x")
    .setRequiredByValidator("value") // field with missing_optional=FAIL extension
    .build();
Defensive patterns

Strategy: validation

Validate before calling

// client-side, before sending
MyRequest req = MyRequest.newBuilder()...build();
for (var fd : req.getDescriptorForType().getFields()) {
  if (fd.hasPresence() && !req.hasField(fd)) {
    throw new IllegalArgumentException("Field with presence must be set: " + fd.getName());
  }
}

Type guard

boolean isFieldSet(com.google.protobuf.Message msg, Descriptors.FieldDescriptor fd) {
  return !fd.hasPresence() || msg.hasField(fd);
}

Try / catch

try {
  stub.call(request);
} catch (StatusRuntimeException e) {
  if (e.getStatus().getCode() == Status.Code.INVALID_ARGUMENT) {
    // inspect trailers for fieldViolation naming the unset field and populate it
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of signalapp/Signal-Server@100ab61c82 (2026-09-09). Data as JSON: /api/errors/9c46a3cdebaa3123. Report an issue: GitHub.

Appendix: source

Thrown at service/src/main/java/org/whispersystems/textsecuregcm/grpc/ValidatingInterceptor.java:141

        // Checking for repeated fields also handles maps, because maps are syntax sugar for repeated MapEntries
        // which themselves are Messages that will be recursively descended.
        for (final Object o : list) {
          validateMessage(o);
        }
      } else if (fd.hasPresence() && msg.hasField(fd)) {
        // If the field has presence information and is present, recursively validate it. Not all fields have
        // presence, but we only validate Message type fields anyway, which always have explicit presence.
        validateMessage(msg.getField(fd));
      }
    }
  }

  private void validateField(final FieldValidator<?> validator, final Object extensionValue, final Message msg, final Descriptors.FieldDescriptor fd) {
    // for the fields with an `optional` modifier, checking if the field was set
    // and if not, checking if extension allows missing optional field
    if (fd.hasPresence() && !msg.hasField(fd)) {
      switch (validator.getMissingOptionalAction()) {
        case FAIL -> throw fieldViolation(fd, validator.getExtensionName(), "extension requires a value to be set");
        case SUCCEED -> {
          return;
        }
        case VALIDATE_DEFAULT_VALUE -> {}
      }
    }

    try {
      validator.validate(extensionValue, fd, msg.getField(fd));
    } catch (FieldValidationException e) {
      throw fieldViolation(fd, validator.getExtensionName(), e.getMessage());
    }
  }

  private void validateRepeatedElementConstraints(
      final ElementConstraint elementConstraint,
      final Message message,
      final Descriptors.FieldDescriptor fd) {

View on GitHub (pinned to 100ab61c82)