Published at: 2025-10-30
Validation Rules
1. Validation Rules — Use Cases
When creating or editing record data, the system validates the page inputs before saving to ensure they are valid and meet business requirements. For example, when saving an Account record, you can validate the Mobile Phone field; if it fails validation, the validation rule can block the save.
2. How to Use
2.1 Navigation
Standard Object / Custom Object Management -> Validation Rules
2.2 Basic Validation Rule Settings
- Applicable actions
- New record: the rule will block saves initiated via the New button
- Edit record: the rule will block saves initiated via the Edit button on the detail page
- When a validation rule evaluates to true, it triggers the blocking behavior
- If configured to block, the system displays the message and prevents saving
- If configured not to block, the system displays the message and allows the user to choose whether to continue saving
2.3 Advanced Configuration
- Advanced Mode: enable Advanced Mode when your formula references fields on the Primary Object and fields on lookup-related objects. Note: referencing aggregated or calculated fields on related objects or on the Primary Object in formulas can introduce latency — the validation rule may take some time before it becomes effective after configuration.
2.4 AI-assisted Formula Generation
2.5 When Fields in Formulas Are Blank
For formula fields that are not of type Number, Currency, or Percent, the "Treat blank fields as zero in formulas" option does not apply — blank values participate in the formula as blank. If a blank value participates in arithmetic or logical operations, the formula will error and return blank. Use explicit null-check functions to handle blanks for non-number/non-currency/non-percent fields.
- Supported field types for insertion: Currency, Date, DateTime, Email, Address, Long Text, Decimal, Number, Percent, Mobile Phone, Picklist (Single Select), Single-line Text, Boolean, URL, Location, Check-in Component, Payment Component, Formula fields, Roll-up fields, and calculation/roll-up fields from lookup-related objects
- Supported functions:
| Return Type | Operator / Function | Parameters | Description | Notes / Example | |
|---|---|---|---|---|---|
| General | () | Group expressions to indicate precedence | |||
| Depends on input | IF(logical_test, value_if_true, value_if_false) | 3 params. Types: first must be Boolean; second and third must be the same type | If logical_test is true, return value_if_true; otherwise return value_if_false. The two return values must be the same type. | Example: 34 = IF(true, 34, 52) | |
| CASE(expression, value1, result1, value2, result2, ..., else_result) | Variable params. result(n) and else_result must be the same type | Compares expression to value(n); returns matching result(n). If no match, returns else_result. Return type equals result types. | Example: 33 = CASE(3, 2, 2, 3, 33, 1.3) | ||
| NULLVALUE(expression, substitute_expression) | 2 params. First may be null; second can be any type | If expression is null, returns substitute_expression; otherwise returns expression. Return type equals the second parameter's type. | Example: 1 = NULLVALUE(Null, 1) Null = NULLVALUE(5, 1) | ||
| Numeric | +,-,*,/ | 2 params. Types: Number, Percent, Currency | Basic arithmetic operations | Example: 6 = (3+2)*6/5 | |
| - (date - date) | 2 params. Both Date. Result in days | Subtract two dates; returns difference in days | Example: if a = 1982-04-13 and b = 1982-03-20 then 24 = a - b | ||
| - (datetime - datetime) | 2 params. Both DateTime. Result in hours | Subtract two datetimes; returns difference in hours | Example: if a = 1982-04-13 17:00:00 and b = 1982-04-12 15:00:00 then 26 = a - b | ||
| - (time - time) | 2 params. Both Time. Result in hours | Subtract two times; returns difference in hours | Example: if a = 17:00:00 and b = 15:00:00 then 2 = a - b | ||
| VALUE(string) | 1 param: Text | Convert a numeric string to Number. Supports negative and decimals. Returns blank if conversion fails. | Example: -1982.0413 = VALUE('-1982.0413') Null = VALUE('aaa') | ||
| MIN(number1, number2) | 2 numeric params | Return the smaller of the two numbers | Example: 4 = MIN(4, 13) | ||
| MAX(number1, number2) | 2 numeric params | Return the larger of the two numbers | Example: 13 = MAX(4, 13) | ||
| MULTIPLE(number1, number2) | 2 numeric params | Return number1 * number2 | Example: 52 = MULTIPLE(4, 13) | ||
| MOD(number1, number2) | 2 numeric params | Return the remainder of number1 / number2 | Example: 1 = MOD(13, 4) | ||
| ADDS(number1, number2) | 2 numeric params | Return number1 + number2 | Example: 17 = ADDS(13, 4) | ||
| SUBTRACTS(number1, number2) | 2 numeric params | Return number1 - number2 | Example: 9 = SUBTRACTS(13, 4) | ||
| YEAR(date) | 1 param: Date or DateTime | Return the year component | Example: if a = 1982-04-13 then 1982 = YEAR(a) | ||
| MONTH(date) | 1 param: Date or DateTime | Return the month component | Example: if a = 1982-04-13 then 4 = MONTH(a) | ||
| DAY(date) | 1 param: Date or DateTime | Return the day component | Example: if a = 1982-04-13 then 13 = DAY(a) | ||
| LEN(text) | 1 param: Text | Return string length | Example: 6 = LEN('xiaoke') | ||
| Percent | +,-,*,/ | 2 params. Types: Number, Percent, Currency | Arithmetic with percent-aware return | ||
| Date/DateTime interval | YEARS(number) | 1 numeric param | Specify years for date/datetime arithmetic | Example: TODAY() + YEARS(1) | |
| MONTHS(number) | 1 numeric param | Specify months for date/datetime arithmetic | Example: MONTHS(2) | ||
| DAYS(number) | 1 numeric param | Specify days for date/datetime arithmetic | Example: DAYS(4) | ||
| HOURS(number) | 1 numeric param | Specify hours for datetime/time arithmetic | Example: HOURS(4) | ||
| MINUTES(number) | 1 numeric param | Specify minutes for datetime/time arithmetic | Example: MINUTES(4) | ||
| Date | +,- | 2 params. First Date; second a YEARS/MONTHS/DAYS interval | Date arithmetic; returns a Date | Example: CreateDate + DAYS(4) | |
| DATE(year, month, day) | 3 numeric params | Build a Date from numbers | Example: DATE(1982, 4, 13) | ||
| DATEVALUE(string) | 1 string param | Convert a string to Date | Example: DATEVALUE('1982-04-13') | ||
| TODAY() | none | Return current date | |||
| DATETIMETODATE(datetime) | 1 DateTime param (formula) | Extract the Date portion from a DateTime | Example: DATETIMETODATE('1982-04-13 17:00:00') | ||
| DateTime | +,- | 2 params. First DateTime; second an interval built from YEARS, MONTHS, DAYS, HOURS, MINUTES | Datetime arithmetic; returns a DateTime | Example: DeadlineTime - DAYS(1) | |
| DATETIMEVALUE(string) | 1 string param | Convert a string to DateTime | Example: DATETIMEVALUE('2001-08-24 15:45:25') | ||
| NOW() | none | Return current date and time | |||
| Time | +,- | 2 params. First a DateTime or Time; second HOURS/MINUTES interval | Time arithmetic; result constrained between 00:00 and 23:59 | Example: submitDailyReport - HOURS(1) | |
| DATETIMETOTIME(datetime) | 1 DateTime param (formula) | Extract the Time portion from a DateTime | Example: DATETIMETOTIME('1982-04-13 17:02:40') | ||
| Text | & | 2 text params | Concatenate strings | Example: 'ZhangSan' & 'LiSi' = 'ZhangSanLiSi' | |
| '' | 1 string param | Insert single-line text literal | Example: 'single-line text' | ||
| '''''' | 1 string param | Insert multi-line text literal | Example: '''multi-line text''' | ||
| NUMBERSTRING(number) | 1 numeric or currency param | Convert a number to Chinese uppercase numerals for display | Example: NUMBERSTRING(198204.13) = '壹拾玖万捌仟贰佰零肆点壹叁' | ||
| NUMBERSTRINGRMB(number) | 1 numeric or currency param | Convert number to Chinese uppercase currency (supports units down to jiao and fen) | Example: NUMBERSTRINGRMB(198204.13) = '壹拾玖万捌仟贰佰零肆元壹角叁分' | ||
| Boolean | <, >, >=, <=, ≠ | 2 params. Types: Number, Percent, Currency | Numeric comparisons return true or false | Example: true = 1 < 2 ; false = 2 < 1 | |
| AND(boolean1, boolean2, ...) | Multiple Boolean params | Logical AND. Returns true if all inputs are true. | Example: true = AND(2 > 1, 5 > 3) | ||
| OR(boolean1, boolean2, ...) | Multiple Boolean params | Logical OR. Returns true if any input is true. | Example: true = OR(2 > 1, 5 < 3) | ||
| NOT(boolean) | 1 Boolean param | Logical NOT. Returns the inverse boolean value. | Example: false = NOT(2 > 1) | ||
| ISNULL(expression) | 1 param, any type | Returns true if expression is null; otherwise false | Example: false = ISNULL(5) | ||
| ISNUMBER(string) | 1 string param | Return true if the string can be converted to a number | Example: true = ISNUMBER('5') | ||
| STARTWITH(string1, string2) | 2 string params | Return true if string1 starts with string2 | Example: true = STARTWITH('abcdef', 'ab') | ||
| ENDWITH(string1, string2) | 2 string params | Return true if string1 ends with string2 | Example: true = ENDWITH('aecdab', 'ab') | ||
| EQUALS(string1, string2) | 2 string params | Case-sensitive string equality | Example: true = EQUALS('aecdab', 'aecdab') | ||
| CONTAINS(string1, string2) | 2 string params | Return true if string2 is contained in string1 | Example: false = CONTAINS('abcdef', 'kl') |
2.5 Notes
- You can define multiple validation rules; the system evaluates them in creation order
- You can enable or disable validation rules; disabled rules do not apply
3. Troubleshooting — Common Validation Rule Issues
3.1 Validation Rule Using Roll-up Fields Does Not Take Effect
3.1.1 Scenario
1. The rule does not block on New, but blocks on Edit.
2. When creating, the roll-up field displays a value that meets the validation condition, but the validation rule does not trigger.
3.1.2 Root Cause
The validation rule directly or indirectly references a roll-up field from a lookup-related object where that roll-up aggregates one of the following: a field on the current object, a field on the current object's Primary Object, or a field on the current object's lookup-related object. During edit, the system evaluates the validation rule using the previously saved roll-up value from the database — not the real-time value currently shown on the page — so the validation may differ. During create, the database does not yet contain the roll-up value, so the rule will not take effect.
- Use the root cause above to better understand and reproduce the scenario
Example: An Order Line validation rule blocks when Available Quantity < 0. Current data: Product record (Mineral Water) — Total Inventory = 20, Sold = 0. When creating an Order and adding an Order Line: Product = Mineral Water, Line Quantity = 30. The calculated Available Quantity shows -10 on the page. Based on the rule (Available Quantity < 0) the save should be blocked, but the record is saved successfully.
3.1.3 Resolution
Invoke the roll-up field validation before the save action in the New and Edit save buttons — use a pre-save validation function that checks roll-up values to block the save if needed.
3.2 Validation Using Record Owner's Primary Department Does Not Take Effect
3.2.1 Scenario
1. Using the record’s Owner Primary Department on the same object
2. Using the Owner’s department on an associated object’s owner
3. Combining the record Owner’s Primary Department and a related owner’s department
3.2.2 Root Cause
When creating a new record, the Owner Primary Department and the Owner Department fields are empty until after the record is submitted (validation runs before those fields are populated in the database).
3.2.3 Resolution
Configure a pre-save validation function on the New and Edit save buttons to lookup the Owner ID and retrieve the department information from the user record. This requires a more advanced implementation — contact your system implementer for configuration help.
3.3 If a Record Violates a Validation Rule, How Was It Created?
3.3.1 Scenario
A registration form object has a validation rule: "Cannot save if Student Company Email and Student Personal Email are both blank." But you find existing records with blank emails.
3.3.2 Root Causes
Cause 1: The record originally had values; later a function cleared those fields, bypassing validation.
Cause 2: The record was created before the validation rule was added.
3.3.3 Resolution
Method 1: Review the record audit history to see if a function or automation changed the fields.
Method 2: Compare the record creation timestamp with the validation rule creation time.
3.4 Validation Using Formula / Roll-up Fields: Rule Does Not Apply When Value Is Blank
3.4.1 Scenario
The Order object has a validation rule: "Order Total (Original Currency) <= 0 — cannot save."
However, when creating a new Order without filling the Order Total (Original Currency), the record saves successfully.
3.4.2 Root Cause
Users may assume a blank numeric field equals zero, but blanks do not participate in validation calculations.
3.4.3 Resolution
Enable "Treat blank fields as zero in formulas" for the validation formula, so blanks are treated as 0 during evaluation.
3.5 "Treat Blanks as Zero" Not Taking Effect for Certain Field Types
3.5.1 Scenario
On the "Equipment Loan/Return" object a validation rule checks Return Date - Request Date > 180 and "Treat blank fields as zero" is enabled. The validation should evaluate as false (so not block), but the submission is blocked.
3.5.2 Root Cause
For formula fields that are not Number, Currency, or Percent types, the "Treat blank fields as zero" option does not apply. Those blanks are treated as null in the formula. If a null participates in arithmetic or logical evaluation, the formula errors and returns null. Therefore the validation behaves unexpectedly. You must explicitly handle non-numeric blanks using null-check functions.
3.5.3 Resolution
Use ISNULL (or equivalent null-check) to handle blanks for non-number, non-currency, and non-percent fields within the formula.