{"record":{"id":"586c46cea864877b","repo":"signalapp/Signal-Server","slug":"field-value-is-d-but-expected-to-be-within-the-586c46","errorCode":null,"errorMessage":"field value is [%d] but expected to be within the [%d, %d] range","messagePattern":"field value is \\[(.+?)\\] but expected to be within the \\[(.+?), (.+?)\\] range","errorType":"validation","errorClass":"FieldValidationException","httpStatus":null,"severity":"error","filePath":"service/src/main/java/org/whispersystems/textsecuregcm/grpc/validators/SizeFieldValidator.java","lineNumber":34,"sourceCode":"  public SizeFieldValidator() {\n    super(\"size\", Set.of(\n        Descriptors.FieldDescriptor.Type.STRING,\n        Descriptors.FieldDescriptor.Type.BYTES\n    ), MissingOptionalAction.VALIDATE_DEFAULT_VALUE, true);\n  }\n\n  @Override\n  protected Range resolveExtensionValue(final Object extensionValue) throws FieldValidationException {\n    final SizeConstraint sizeConstraint = (SizeConstraint) extensionValue;\n    final int min = sizeConstraint.hasMin() ? sizeConstraint.getMin() : 0;\n    final int max = sizeConstraint.hasMax() ? sizeConstraint.getMax() : Integer.MAX_VALUE;\n    return new Range(min, max);\n  }\n\n  @Override\n  protected void validateBytesValue(final Range range, final ByteString fieldValue) throws FieldValidationException {\n    if (fieldValue.size() < range.min() || fieldValue.size() > range.max()) {\n      throw new FieldValidationException(\"field value is [%d] but expected to be within the [%d, %d] range\".formatted(\n          fieldValue.size(), range.min(), range.max()));\n    }\n  }\n\n  @Override\n  protected void validateStringValue(final Range range, final String fieldValue) throws FieldValidationException {\n    if (fieldValue.length() < range.min() || fieldValue.length() > range.max()) {\n      throw new FieldValidationException(\"field value is [%d] but expected to be within the [%d, %d] range\".formatted(\n          fieldValue.length(), range.min(), range.max()));\n    }\n  }\n\n  @Override\n  protected void validateRepeatedField(final Range range, final Descriptors.FieldDescriptor fd, final List<?> repeated) throws FieldValidationException {\n    final int size = repeated.size();\n    if (size < range.min() || size > range.max()) {\n      throw new FieldValidationException(\"field value is [%d] but expected to be within the [%d, %d] range\".formatted(\n          size, range.min(), range.max()));","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/signalapp/Signal-Server/blob/100ab61c82627582c867d19e1c0561ba2781e927/service/src/main/java/org/whispersystems/textsecuregcm/grpc/validators/SizeFieldValidator.java#L16-L52","documentation":"SizeFieldValidator.validateBytesValue throws FieldValidationException when a bytes proto field's byte length is outside the annotated [min, max] size range. The message shows the actual byte size and allowed bounds.","triggerScenarios":"Sending a Signal gRPC request with a bytes field (e.g. encrypted payload, profile key, sender certificate) that is too short or longer than the annotated max.","commonSituations":"Truncated base64 decoding; oversized attachments/metadata payloads; sending empty byte strings where a minimum length is required; protocol version changes altering expected payload sizes.","solutions":["Check fieldValue.toByteArray().length against the documented min/max before sending","Trim or chunk oversized payloads; regenerate truncated ones","If the size constraint is wrong for your use case, adjust the proto size annotation server-side"],"exampleFix":"// before\nbuilder.setProfileKey(profileKeyBytes); // may be any length\n// after\nif (profileKeyBytes.length != 32) {\n  throw new IllegalArgumentException(\"profile key must be 32 bytes\");\n}\nbuilder.setProfileKey(profileKeyBytes);","handlingStrategy":"validation","validationCode":"int len = bytes == null ? 0 : bytes.length; if (len < MIN || len > MAX) throw new IllegalArgumentException(\"byte size \" + len + \" outside [\" + MIN + \", \" + MAX + \"]\");","typeGuard":null,"tryCatchPattern":"try { stub.call(request); } catch (StatusRuntimeException e) { if (e.getStatus().getCode() == Status.Code.INVALID_ARGUMENT && e.getMessage().contains(\"range\")) { /* handle bad size */ } }","preventionTips":["Verify decoded byte lengths after base64 operations","Assert fixed-size fields (keys, certificates) have exact expected lengths","Check proto size annotations before constructing payloads"],"tags":["grpc","validation","size","bytes"],"backgroundTag":"payload-too-large","analyzedSha":"100ab61c82627582c867d19e1c0561ba2781e927","analyzedAt":"2026-09-09T13:29:47.883Z","contentChangedAt":"2026-09-09T13:29:47.883Z","schemaVersion":2},"datasetVersion":"2026-09-16T14:17:13.074Z"}