User data field validation - infobip/mobile-messaging-sdk-android GitHub Wiki
Starting from version 14.7.2, the Mobile Messaging SDK enforces validation of all user data fields against the Customer Profiles API (formerly People API) limits before sending data to the server. This ensures data integrity and provides immediate feedback when field constraints are violated.
The following limits are enforced based on the Customer Profiles API (formerly People API) specification:
| Field | Limit | Description |
|---|---|---|
firstName |
255 characters | Person's first name |
lastName |
255 characters | Person's last name |
middleName |
50 characters | Person's middle name |
externalUserId |
256 characters | Unique ID for a person from your external system |
emails |
100 emails | Maximum number of email addresses per person |
phones |
100 phone numbers | Maximum number of phone numbers per person |
customAttributes (per value) |
4096 characters | Maximum length per custom attribute value |
When using synchronous operations with a ResultListener, validation errors are returned immediately in the error callback:
User user = new User();
user.setFirstName(veryLongString); // > 255 characters
mobileMessaging.saveUser(user, new MobileMessaging.ResultListener<User>() {
@Override
public void onResult(Result<User> result) {
if (result.isSuccess()) {
// User saved successfully
User savedUser = result.getData();
} else {
// Validation error or other error
MobileMessagingError error = result.getError();
Log.e("TAG", "Error: " + error.getMessage());
}
}
});Error handling:
- If validation fails, the
ResultListenerwill receive aResultwith an error - The error message will detail which fields violated the constraints
- No partial updates are made - if any field is invalid, the entire operation is rejected
- The error message includes a link to the API documentation for reference
When using asynchronous operations without a ResultListener, validation exceptions are not thrown to the caller:
User user = new User();
user.setFirstName(veryLongString); // > 255 characters
// This call will fail silently - no exception is thrown
mobileMessaging.saveUser(user);Important notes:
- Validation errors are logged but not thrown as exceptions
- The operation will fail silently from the caller's perspective
- If you need error handling, always use the synchronous variant with a ResultListener
User user = new User();
user.setFirstName("John");
user.setLastName("Doe");
user.setMiddleName("M");
user.setExternalUserId("user123");
user.setEmails(Collections.singleton("[email protected]"));
user.setPhones(Collections.singleton("+1234567890"));
Map<String, CustomAttributeValue> customAttributes = new HashMap<>();
customAttributes.put("subscriptionLevel", new CustomAttributeValue("premium"));
user.setCustomAttributes(customAttributes);
// This will succeed
mobileMessaging.saveUser(user, new MobileMessaging.ResultListener<User>() {
@Override
public void onResult(Result<User> result) {
if (result.isSuccess()) {
Log.d("TAG", "User saved successfully");
}
}
});User user = new User();
// This string is 260 characters - exceeds the 255 limit
String veryLongFirstName = "a".repeat(260);
user.setFirstName(veryLongFirstName);
mobileMessaging.saveUser(user, new MobileMessaging.ResultListener<User>() {
@Override
public void onResult(Result<User> result) {
if (!result.isSuccess()) {
// Validation error will be caught here
MobileMessagingError error = result.getError();
Log.e("TAG", "Validation failed: " + error.getMessage());
// Error message will contain:
// "User data validation failed:
// - firstName exceeds maximum length of 255 characters (actual: 260)
// Please check the field limits at: https://www.infobip.com/docs/api/customer-engagement/people/update-a-person"
}
}
});User user = new User();
Set<String> emails = new HashSet<>();
for (int i = 0; i < 105; i++) {
emails.add("email" + i + "@infobip.com");
}
user.setEmails(emails); // Exceeds 100 email limit
mobileMessaging.saveUser(user, new MobileMessaging.ResultListener<User>() {
@Override
public void onResult(Result<User> result) {
if (!result.isSuccess()) {
Log.e("TAG", "Error: " + result.getError().getMessage());
// Error message will contain:
// "User data validation failed:
// - emails count exceeds maximum of 100 (actual: 105)
// Please check the field limits at: https://www.infobip.com/docs/api/customer-engagement/people/update-a-person"
}
}
});User user = new User();
user.setFirstName("a".repeat(260)); // Too long
user.setMiddleName("b".repeat(55)); // Too long
user.setExternalUserId("c".repeat(300)); // Too long
mobileMessaging.saveUser(user, new MobileMessaging.ResultListener<User>() {
@Override
public void onResult(Result<User> result) {
if (!result.isSuccess()) {
// All validation errors will be reported together
Log.e("TAG", result.getError().getMessage());
// Error message will contain all three violations:
// "User data validation failed:
// - firstName exceeds maximum length of 255 characters (actual: 260)
// - middleName exceeds maximum length of 50 characters (actual: 55)
// - externalUserId exceeds maximum length of 256 characters (actual: 300)
// Please check the field limits at: https://www.infobip.com/docs/api/customer-engagement/people/update-a-person"
}
}
});Field validation is applied to the following SDK methods:
MobileMessaging.saveUser(User user, ResultListener<User> listener)-
MobileMessaging.saveUser(User user)(async - errors not reported to caller)
MobileMessaging.personalize(UserIdentity userIdentity, UserAttributes userAttributes, ResultListener<User> listener)MobileMessaging.personalize(UserIdentity userIdentity, UserAttributes userAttributes, boolean forceDepersonalize, ResultListener<User> listener)
- Always use ResultListener for production code - This ensures you can handle validation errors gracefully
- Validate data on the client side - Consider adding input validation in your UI to prevent users from entering data that exceeds limits
- Handle errors gracefully - Show user-friendly error messages when validation fails
- Test edge cases - Test with data at the boundary limits (e.g., exactly 255 characters) to ensure your app handles limits correctly
- Log validation errors - Always log validation errors for debugging purposes
If you're upgrading from a previous version:
// Invalid data would be sent to the server
// Server would reject it and return an error
User user = new User();
user.setFirstName(veryLongString);
mobileMessaging.saveUser(user, listener);
// Error would come back from the server after network round-trip// Invalid data is caught immediately before sending to server
User user = new User();
user.setFirstName(veryLongString);
mobileMessaging.saveUser(user, listener);
// Error is returned immediately in the listener, no network request madeCustom attributes have a per-value limit of 4096 characters. The validation checks the string representation of the value:
Map<String, CustomAttributeValue> customAttributes = new HashMap<>();
// Valid - string value
customAttributes.put("description", new CustomAttributeValue("Short description"));
// Valid - number value (converted to string for validation)
customAttributes.put("age", new CustomAttributeValue(25));
// Valid - boolean value (converted to string for validation)
customAttributes.put("isPremium", new CustomAttributeValue(true));
// Invalid - string too long
customAttributes.put("longText", new CustomAttributeValue("a".repeat(5000))); // Will fail validation
user.setCustomAttributes(customAttributes);Validation errors are logged at ERROR level:
E/MobileMessaging: USER DATA VALIDATION ERROR
org.infobip.mobile.messaging.mobileapi.user.UserDataValidationException: User data validation failed:
- firstName exceeds maximum length of 255 characters (actual: 260)
Please check the field limits at: https://www.infobip.com/docs/api/customer-engagement/people/update-a-person
When writing tests, you can catch validation exceptions:
@Test
public void testInvalidFirstName() {
User user = new User();
user.setFirstName("a".repeat(260));
mobileMessaging.saveUser(user, new MobileMessaging.ResultListener<User>() {
@Override
public void onResult(Result<User> result) {
assertFalse(result.isSuccess());
assertNotNull(result.getError());
assertTrue(result.getError().getMessage().contains("firstName"));
}
});
}Q: My saveUser call is failing but I don't see any error
A: Make sure you're using the synchronous variant with a ResultListener. The async variant (without listener) will not report errors to the caller.
Q: Can I disable validation? A: No, validation cannot be disabled as it enforces API constraints that would otherwise be rejected by the server.
Q: What happens if I call saveUser without a listener?
A: The validation will still occur, but errors will only be logged and not reported to your code. Use a ResultListener if you need error handling.
Q: Are partial updates allowed if some fields are valid? A: No, validation follows an all-or-nothing approach. If any field is invalid, the entire operation is rejected with no partial updates.
Q: How can I check if my data will pass validation before calling saveUser?
A: You can use the UserDataValidator.validate() methods directly (though this is an internal API):
try {
UserDataValidator.validate(user);
// Data is valid
} catch (UserDataValidationException e) {
// Data is invalid
Log.e("TAG", e.getMessage());
}