{"record":{"id":"6bf7256fced04c69","repo":"signalapp/Signal-Server","slug":"byte-array-length-is-d-but-expected-to-be-one-o","errorCode":null,"errorMessage":"byte array length is [%d] but expected to be one of %s","messagePattern":"byte array length is \\[(.+?)\\] but expected to be one of (.+?)","errorType":"validation","errorClass":"FieldValidationException","httpStatus":null,"severity":"error","filePath":"service/src/main/java/org/whispersystems/textsecuregcm/grpc/validators/ExactlySizeFieldValidator.java","lineNumber":35,"sourceCode":"        Descriptors.FieldDescriptor.Type.STRING,\n        Descriptors.FieldDescriptor.Type.BYTES\n    ), MissingOptionalAction.VALIDATE_DEFAULT_VALUE, true);\n  }\n\n  @Override\n  protected Set<Integer> resolveExtensionValue(final Object extensionValue) {\n    //noinspection unchecked\n    return Set.copyOf((List<Integer>) extensionValue);\n  }\n\n  @Override\n  protected void validateBytesValue(\n      final Set<Integer> permittedSizes,\n      final ByteString fieldValue) throws FieldValidationException {\n    if (permittedSizes.contains(fieldValue.size())) {\n      return;\n    }\n    throw new FieldValidationException(\"byte array length is [%d] but expected to be one of %s\".formatted(fieldValue.size(), permittedSizes));\n  }\n\n  @Override\n  protected void validateStringValue(\n      final Set<Integer> permittedSizes,\n      final String fieldValue) throws FieldValidationException {\n    if (permittedSizes.contains(fieldValue.length())) {\n      return;\n    }\n    throw new FieldValidationException(\"string length is [%d] but expected to be one of %s\".formatted(fieldValue.length(), permittedSizes));\n  }\n\n  @Override\n  protected void validateRepeatedField(\n      final Set<Integer> permittedSizes,\n      final Descriptors.FieldDescriptor fd,\n      final List<?> repeated) throws FieldValidationException {\n    if (permittedSizes.contains(repeated.size())) {","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/signalapp/Signal-Server/blob/100ab61c82627582c867d19e1c0561ba2781e927/service/src/main/java/org/whispersystems/textsecuregcm/grpc/validators/ExactlySizeFieldValidator.java#L17-L53","documentation":"ExactlySizeFieldValidator.validateBytesValue checks that a proto bytes field's ByteString is exactly one of a configured set of permitted sizes. If fieldValue.size() is not in permittedSizes, it throws FieldValidationException with a formatted message including the actual and permitted sizes.","triggerScenarios":"gRPC requests with bytes fields (e.g. profile keys, storage keys, receipt data) whose decoded byte length does not match the required size(s) enforced via proto validator annotations.","commonSituations":"Sending keys of wrong length (e.g. 16 vs 32 bytes) after generating them with a different algorithm; truncating or padding data in client code; version mismatches where the server tightened required sizes.","solutions":["Check the required length(s) from the error's permitted sizes list and regenerate the value at the correct length","Verify client-side byte arrays are exactly the expected size before encoding into the proto","Ensure the value wasn't truncated/extended by an intermediate encode/decode step","Align client library version with the server's expected field sizes"],"exampleFix":"// before\nbyte[] key = new byte[16];\n// after\nbyte[] key = new byte[32]; // matches permittedSizes [32]","handlingStrategy":"validation","validationCode":"if (!permittedSizes.contains(bytes.length)) {\n  throw new IllegalArgumentException(\"expected bytes length in \" + permittedSizes + \", got \" + bytes.length);\n}","typeGuard":null,"tryCatchPattern":"try {\n  grpcStub.call(request);\n} catch (StatusRuntimeException e) {\n  if (e.getStatus().getCode() == Code.INVALID_ARGUMENT && e.getStatus().getDescription().contains(\"byte array length\")) {\n    // regenerate the bytes at the permitted size\n  }\n}","preventionTips":["Check key/byte-array lengths right after generation","Consult the proto validator annotation to learn required sizes","Avoid encode/decode round-trips that change array length"],"tags":["grpc","validation","bytes","size-limit"],"backgroundTag":"value-out-of-range","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"}