Advanced validation rules use a formula-based syntax to define conditions that the data entered into a field must satisfy. Conditions must resolve to True or False values.
Validation rules are evaluated using tenant-level permissions, not the current user's permissions. This means validation rules can access linked fields and related data that the user performing the validation (e.g., registration) may not have permission to view. Users performing the action may be able to derive information about linked data based on evaluating the rule. For example, a user can derive from a rule this.fields.linked_entity.fields.status = "Approved", that the linked_entity entity has a field called status and whether or not it is “Approved”.
All validation rules should be written with the expectation that users performing the validation (e.g. registration) can read both the validation rule and the validation results, including any implications about the object being validated.
Examples
The list below contains examples of the validation goal and the syntax for the rule.
Quantity must be positive:
this.fields.quantity > 0
Expiration date must be in the future:
this.fields.expiration_date > TODAY()
Linked entity must be in Approved status:
this.fields.linked_entity.fields.status = "Approved"
- If item is hazardous, safety review data is required:
IF(this.fields.is_hazardous = true, ISPRESENT(this.fields.safety_review_date), true)
Syntax
Literal Types
Type |
Descriptions |
Examples |
|---|---|---|
Text |
String values enclosed in double quotes. |
|
Integer |
Whole numbers. |
|
Decimal |
Numbers with decimal points. Supports scientific notation. |
|
Boolean |
True or False values. |
|
Object |
Reference to a Benchling object by its API identifier. |
|
List |
Collection of values. |
|
Operators
Arithmetic Operators
Addition and subtraction also work with dates (see date arithmetic below).
Operator |
Description |
Example |
Result |
|---|---|---|---|
|
Addition |
|
|
|
Subtraction |
|
|
|
Multiplication |
|
|
|
Division |
|
|
|
Positive |
|
|
|
Negative |
|
|
Date arithmetic
You can add or subtract integers from date/datetime values. The integer represents the number of days to add or subtract.
this.fields.start_date + 30 // 30 days after start_date this.fields.expiration_date - 7 // 7 days before expiration_date
Comparison operators
Comparison operators work with numbers, text, dates, booleans, and objects.
Operator |
Description |
Supported Types |
|---|---|---|
|
Equal to |
All types |
|
Not equal to |
All types |
|
Less than |
Numbers, Dates |
|
Greater than |
Numbers, Dates |
|
Less than or equal |
Numbers, Dates |
|
Greater than or equal |
Numbers, Dates |
Examples:
this.fields.quantity >= 100 "hello" = "hello" "hello" <> "Hello" this.fields.status = "Active" true = true true <> false this.fields.is_active = true this.fields.expiration_date > TODAY() this.fields.start_date <= this.fields.end_date this.fields.entity_field = @bfi_v33senwS0l [1, 2, 3] = [1, 2, 3] [1, 2, 3] <> [3, 2, 1]
Functions
Function names are case-insensitive (e.g. AND, And, and and are all equivalent).
Logical Functions
AND
Returns true if all conditions are true.
Syntax: AND(condition1, condition2, ...)
Arguments: Two to five boolean expressions
Returns: Boolean
Examples:
AND(this.fields.quantity > 0, this.fields.status = "Active") AND(ISPRESENT(this.fields.lot_number), this.fields.expiration_date > TODAY())
OR
Returns true if any condition is true.
Syntax: OR(condition1, condition2, ...)
Arguments: Two to five boolean expressions
Returns: Boolean
Examples:
OR(this.fields.status = "Active", this.fields.status = "Pending") OR(this.fields.priority = "High", this.fields.quantity < 10)
NOT
Returns the opposite of a boolean condition.
Syntax: NOT(condition)
Arguments: A single boolean expression
Returns: Boolean
Examples:
NOT(this.fields.is_archived = true) NOT(ISBLANK(this.fields.lot_number))
Conditional Functions
IF
Returns one value if a condition is true, and another value if it's false.
Syntax: IF(condition, value_if_true, value_if_false)
Arguments:
condition– A boolean expressionvalue_if_true– Value returned when condition is truevalue_if_false– Value returned when condition is false
Returns: The type of the value arguments
Examples:
IF(this.fields.quantity > 100, "High", "Low") = "High" IF(this.fields.is_hazardous = true, this.fields.safety_review_date, this.fields.created_date) > TODAY() - 365
Date Functions
TODAY
Returns the current date according to UTC timezone. Note: Items that become invalid over time will be flagged on a weekly basis.
Syntax: TODAY()
Arguments: None
Returns: Date
Examples:
this.fields.expiration_date > TODAY() this.fields.review_date <= TODAY() + 30
Schema Functions
HASSCHEMA
Checks if an object has a specific schema.
Syntax: HASSCHEMA(object, "schema_api_id")
Arguments:
object– A Benchling object (entity, container, etc.)schema_api_id– The API identifier of the schema (text string)
Returns: Boolean
Examples:
HASSCHEMA(this, "ts_1W1mDOvF38") HASSCHEMA(this.fields.linked_entity, "ts_LdjQn6spIQ")
NOTHASSCHEMA
Checks if an object does not have a specific schema.
Syntax: NOTHASSCHEMA(object, "schema_api_id")
Arguments:
object– A Benchling object (entity, container, etc.)schema_api_id– The API identifier of the schema (text string)
Returns: Boolean
Examples:
NOTHASSCHEMA(this, "ts_oaf23sfejL") NOTHASSCHEMA(this.fields.container, "ts_pje9Lfi32L")
Presence Functions
ISPRESENT
Checks if a value is present (not blank or empty).
Syntax: ISPRESENT(value)
Arguments: Any value to check
Returns: Boolean
Behavior:
For text: Returns
trueif not empty stringFor lists/multi-select fields: Returns
trueif at least one item existsFor other types: Returns
trueif value is not null/blank
Examples:
ISPRESENT(this.fields.lot_number) ISPRESENT(this.fields.linked_entities)
ISBLANK
Checks if a value is blank or empty (opposite of ISPRESENT).
Syntax: ISBLANK(value)
Arguments: Any value to check
Returns: Boolean
Behavior:
For text: Returns
trueif empty string or nullFor lists/multi-select fields: Returns
trueif no items existFor other types: Returns
trueif value is null/blank
Examples:
ISBLANK(this.fields.notes) ISBLANK(this.fields.secondary_contacts)
String Functions
LEN
Returns the number of characters in a text value, or the number of items in a list.
Syntax: LEN(value)
Arguments: A text value or a list
Returns: Integer
Behavior: A blank/null value returns 0.
Examples:
LEN("Sample") = 6
LEN(this.fields.lot_number) > 0
LEN(this.fields.linked_entities) = 3
LEFT
Returns the leftmost characters of a text value.
Syntax: LEFT(text, num_chars)
Arguments:
text– A text valuenum_chars– Number of characters to return (must be 0 or greater)
Returns: Text
Behavior: A blank/null text returns an empty string.
Examples:
LEFT(this.fields.barcode, 3) = "LAB"
LEFT("ABC-001", 3) = "ABC"
RIGHT
Returns the rightmost characters of a text value.
Syntax: RIGHT(text, num_chars)
Arguments:
text– A text valuenum_chars– Number of characters to return (must be 0 or greater)
Returns: Text
Behavior: A blank/null text returns an empty string.
Examples:
RIGHT(this.fields.sample_id, 4) = "0001"
RIGHT("SAMPLE-0002", 4) = "0002"
LOWER
Converts text to lowercase.
Syntax: LOWER(text)
Arguments: A text value
Returns: Text
Behavior: A blank/null value returns an empty string.
Examples:
LOWER(this.fields.status) = "active"
LOWER("Disabled") = "disabled"
UPPER
Converts text to uppercase.
Syntax: UPPER(text)
Arguments: A text value
Returns: Text
Behavior: A blank/null value returns an empty string.
Examples:
UPPER(this.fields.code) = "ABC"
UPPER("def") = "DEF"
CONCATENATE
Joins two or more text values into a single string.
Syntax: CONCATENATE(value1, value2, ...)
Arguments: One or more text values
Returns: Text
Behavior: Blank/null values are skipped (treated as empty strings).
Examples:
CONCATENATE(this.fields.prefix, "-", this.fields.suffix) = "LAB-001"
CONCATENATE("LAB", "-", "002") = "LAB-002"
CONTAINS
Checks whether one text value contains another. Case-sensitive.
Syntax: CONTAINS(substring, text)
Arguments:
substring– The text to search fortext– The text to search within
Returns: Boolean
Behavior: Returns false if either value is blank/null.
Examples:
CONTAINS("urgent", this.fields.description)
CONTAINS("urgent review", "urgent") = true
SEARCH
Returns the position of a substring within a text value. Positions start at 1; returns -1 if the substring is not found.
Syntax: SEARCH(search_text, within_text, [starting_at])
Arguments:
search_text– The text to search forwithin_text– The text to search withinstarting_at– (Optional) 1-based position to start searching from (defaults to1, must be 1 or greater)
Returns: Integer
Behavior: Blank/null values are treated as empty strings.
Examples:
SEARCH("-", this.fields.sample_id) > 0
SEARCH("A", this.fields.code, 2) = 5
SEARCH("-", "LAB-001") = 4
List Functions
IN
Checks whether a value is present in a list.
Syntax: IN(value, list)
Arguments:
value– The value to look forlist– A list of values
Returns: Boolean
Behavior: Returns false if the list is blank/null.
Examples:
IN(this.fields.status, ["Active", "Pending"]) IN(this.fields.location, [@loc_abc123, @loc_def456])
HASONEOF
Checks whether a list shares at least one value with another list.
Syntax: HASONEOF(list1, list2)
Arguments:
list1– The list of values to look forlist2– The list to check
Returns: Boolean
Behavior: Returns false if list2 is blank/null.
Examples:
HASONEOF(["priority", "flagged"], this.fields.tags)
Referencing Data
The target item (this)
The keyword this refers to the item being validated. Use it as the starting point for accessing fields.
this.fields.status = "Active" this.fields.quantity > 0
Field access
Access schema fields using the .fields. syntax followed by the field's system name (not the display name).
Syntax: <object>.fields.<system_field_name>
To find a field's system name: open the schema in Benchling, click on the field, and look for the "System Name" or "API Name" property.
Examples:
this.fields.concentration this.fields.storage_temperature this.fields.linked_entity.fields.batch_number
Chaining field access
You can traverse through linked entities by chaining field access:
this.fields.parent_entity.fields.source_organism.fields.species_name
Object References
Reference specific Benchling objects directly using their API identifier prefixed with @. This is useful for:
Comparing against specific locations, projects, or other fixed objects
Validating that a field references a particular item
Syntax: @<api_id>
Examples:
this.fields.entity_a = @bfi_x0X0GZEKPR this.fields.decimal_field = @seq_Hr4dJE3szW.fields.decimal_field
Special Field Accessors
Field Access |
Syntax |
Description |
|---|---|---|
|
|
Retrieves entity that was last created, from a list of entities. |
|
|
Retrieves the items stored within a container |
|
|
Retrieves associated studies. |
|
|
Retrieves pending test orders. |
|
|
Retrieves all ancestor locations. |
Examples:
this.fields.linked_entity.latest.fields.status = "Approved" ISPRESENT(this.contents) ISPRESENT(this.studies)
Lists
Lists are collections of values enclosed in square brackets.
Syntax: [value1, value2, ...]
Examples:
["Active", "Pending", "In Review"] [1, 2, 3, 4, 5] [@loc_abc123, @loc_def456] [] // empty list
Common use cases:
Checking if a list field is not empty:
this.fields.allowed_values <> []
Handling blank or empty values
Validation rules always resolve to true or false, even when a referenced field is blank or empty. Rather than erroring, functions and operators handle blank values with consistent, predictable rules
Category |
Functions / Operators |
Behavior when a value is blank |
|---|---|---|
Ordered comparisons |
|
Blank numbers are treated as |
Equality |
|
Blank compares equal only to another blank. A blank value is never equal to a non-blank value |
Text function |
|
Blank text is treated as an empty string ( |
Tip: To explicitly require that a field is filled in, use ISPRESENT(...). To branch on whether a field is blank, use ISBLANK(...).
Example: If quantity is blank, this.fields.quantity > 0 evaluates as 0 > 0, which is false.
Common Errors
rror |
Cause |
Solution |
|---|---|---|
Field not found |
The field system name is misspelled or doesn't exist on the schema |
Check the field's system name in the schema settings |
Type mismatch |
Comparing incompatible types (e.g., text to number) |
Ensure both sides of comparison are compatible. |
Division by zero |
Dividing by a field or expression that equals zero |
Ensure the divisor cannot be zero. |
Object not found |
Object reference |
Verify the API ID exists and you have read access |
Max nesting depth exceeded |
Formula has more than 5 levels of nested function calls |
Simplify the formula or break into multiple validation rules |
Schema not found |
The schema API ID in |
Verify the schema API ID is correct |
Invalid field access |
Using |
Ensure you're accessing fields on an object, not a primitive value |