{"record":{"id":"becd4555a3f8c49e","repo":"signalapp/Signal-Server","slug":"string-length-is-d-but-expected-to-be-one-of-s","errorCode":null,"errorMessage":"string length is [%d] but expected to be one of %s","messagePattern":"string 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":45,"sourceCode":"\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())) {\n      return;\n    }\n    throw new FieldValidationException(\"list size is [%d] but expected to be one of %s\".formatted(repeated.size(), permittedSizes));\n  }\n}\n","sourceCodeStart":27,"sourceCodeEnd":59,"githubUrl":"https://github.com/signalapp/Signal-Server/blob/100ab61c82627582c867d19e1c0561ba2781e927/service/src/main/java/org/whispersystems/textsecuregcm/grpc/validators/ExactlySizeFieldValidator.java#L27-L59","documentation":"ExactlySizeFieldValidator.validateStringValue checks that a proto string field's length is one of the permitted sizes. If not, it throws FieldValidationException with the actual length and allowed sizes in the message.","triggerScenarios":"gRPC requests with string fields (e.g. device names, tokens, encoded identifiers) annotated with exact-size validation whose character count isn't in permittedSizes — e.g. deviceName longer than 50 chars, or a token of unexpected length.","commonSituations":"Client sending empty strings where a fixed-length token is required; localized names/IDs that exceed the configured length; encoders producing variable-length output (hex vs base64) for the same underlying data.","solutions":["Truncate or otherwise conform the string to one of the lengths listed in the error message","Check whether you should be sending base64url rather than hex (or vice versa) — different lengths for the same data","Validate string length client-side before building the request","Empty string may be the issue: confirm the value is present"],"exampleFix":"// before\nString deviceId = Hex.toStringCondensed(uuidBytes); // 64 chars\n// after\nString deviceId = uuid.toString(); // 36 chars, matches permitted size","handlingStrategy":"validation","validationCode":"if (!permittedSizes.contains(value.length())) {\n  throw new IllegalArgumentException(\"expected string length in \" + permittedSizes + \", got \" + value.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(\"string length\")) {\n    // adjust encoding (hex vs base64url) or truncate to permitted size\n  }\n}","preventionTips":["Match encoding scheme to server expectation (hex=2N chars, base64=~4/3N chars)","Validate lengths locally before building requests","Truncate/pad only where semantics allow it"],"tags":["grpc","validation","string-length","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"}