Validation Rules Syntax

Raven
Raven
  • Updated

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.

"Hello", "Sample-001"

Integer

Whole numbers.

42, -7

Decimal

Numbers with decimal points. Supports scientific notation.

3.14, -0.5, 1.5e10

Boolean

True or False values.

true, FALSE

Object

Reference to a Benchling object by its API identifier.

@bfi_DBYthfm4bP

List

Collection of values.

[1, 2, 3], ["a", "b"]

 

Operators

Arithmetic Operators 

Addition and subtraction also work with dates (see date arithmetic below). 

Operator

 

Description

 

Example

 

Result

 

+

Addition

5 + 3

8

-

Subtraction

10 - 4

6

*

Multiplication

6 * 7

42

/

Division

15 / 3

5.0

+ (unary)

Positive

+5

5

- (unary)

Negative

-5

-5

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 expression

  • value_if_true – Value returned when condition is true

  • value_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 true if not empty string

  • For lists/multi-select fields: Returns true if at least one item exists

  • For other types: Returns true if 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 true if empty string or null

  • For lists/multi-select fields: Returns true if no items exist

  • For other types: Returns true if 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 value

  • num_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 value

  • num_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 for

  • text – 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 for

  • within_text – The text to search within

  • starting_at – (Optional) 1-based position to start searching from (defaults to 1, 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 for

  • list – 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 for

  • list2 – 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

 

.latest

<object>.fields.<field>.latest

Retrieves entity that was last created, from a list of entities.

.contents

<container>.contents

Retrieves the items stored within a container

.studies

<object>.studies

Retrieves associated studies.

.pendingTestOrders

<object>.pendingTestOrders

Retrieves pending test orders.

.allAncestorLocations

<object>.allAncestorLocations

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 0; blank dates are treated as the earliest possible date

Equality

=, <>

Blank compares equal only to another blank. A blank value is never equal to a non-blank value

Text function

LEN, LEFT, RIGHT, LOWER, UPPER, CONCATENATE, SEARCH

Blank text is treated as an empty string (LEN returns 0)

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 @api_id doesn't exist or you lack permission

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 HASSCHEMA doesn't exist

Verify the schema API ID is correct

Invalid field access

Using .fields. on a value that isn't an object

Ensure you're accessing fields on an object, not a primitive value

Was this article helpful?

Have more questions? Submit a request