Salesforce Dictionary - Free Salesforce GlossarySalesforce Dictionary
All articles
Admin·May 3, 2026·14 min read

Salesforce Validation Rules: 20 Real-World Examples Every Admin Should Know

Anatomy of a rule, ISCHANGED/ISNEW/PRIORVALUE/REGEX patterns, 20 working examples, error message best practices, and the gotchas that get missed.

Salesforce Validation Rules — 20 real-world examples every admin should know

TL;DR

  • A Validation Rule is a formula that, when true, blocks save and shows an error.
  • Use the four core functions: ISCHANGED, ISNEW, PRIORVALUE, and REGEX. Together they handle ~90% of cases.
  • 20 working examples below, by category — text format, dates, money, status transitions, cross-object, record-type-specific.
  • Beware: validation rules are skipped by mass transfer and some integration paths. They're the cheapest data-quality enforcement on the platform — but not the only one.

Validation rules are the most underrated tool in the admin toolbox. They cost nothing to build, run instantly, and prevent more bad data than any downstream cleanup script. This guide is the canonical 2026 reference: anatomy, patterns, and 20 working examples you can paste into your org tonight.

Anatomy of a validation rule

A validation rule is two things:

  1. An error condition formula that returns TRUE or FALSE. When TRUE, the save blocks.
  2. An error message that the user sees.
Rule Name:        Email_Required_For_Customer
Error Condition:  AND(
                    ISPICKVAL(Type, 'Customer'),
                    ISBLANK(Email)
                  )
Error Message:    Email is required for Customers.
Error Location:   Field "Email"

The error formula is true → save blocks → user sees the message. The "error location" controls where the message appears (next to a specific field, or at the top of the page).

Anatomy of a validation rule — formula, message, location

The four core functions

Internalize these and you'll write 90% of validation rules without looking anything up.

FunctionUse when
ISCHANGED(field)The field changed in this save (insert: always TRUE; update: depends)
ISNEW()The record is being inserted (not updated)
PRIORVALUE(field)The value of field before this save (only useful with ISCHANGED)
REGEX(text, pattern)Text matches a regex pattern. Best for format validation

Combined examples:

// Block changes to Stage from "Closed Won" back to anything else
AND(
  ISCHANGED(StageName),
  PRIORVALUE(StageName) = 'Closed Won'
)

// Require Email format on creation only (not edits)
AND(
  ISNEW(),
  NOT(REGEX(Email, '^[A-Za-z0-9._-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$'))
)

20 real-world examples

Each is a formula you can paste directly. Adjust field API names to match your org.

Text format (Examples 1–4)

1. Email format validation

AND(
  NOT(ISBLANK(Email)),
  NOT(REGEX(Email, '^[A-Za-z0-9._-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$'))
)

Error: "Email must be in valid format (user@example.com)."

2. US phone number format

AND(
  NOT(ISBLANK(Phone)),
  NOT(REGEX(Phone, '^\\(?\\d{3}\\)?[\\s.-]?\\d{3}[\\s.-]?\\d{4}$'))
)

Error: "Phone must be in (555) 123-4567 format."

3. ZIP code validation (US)

AND(
  NOT(ISBLANK(MailingPostalCode)),
  NOT(REGEX(MailingPostalCode, '^\\d{5}(-\\d{4})?$'))
)

Error: "ZIP must be 5 digits or 5+4 (12345 or 12345-6789)."

4. No special characters in account name

NOT(REGEX(Name, '^[A-Za-z0-9\\s.,&\\-\']+$'))

Error: "Account Name can only contain letters, numbers, spaces, and standard punctuation."

Dates (Examples 5–8)

5. Close Date can't be in the past on create

AND(
  ISNEW(),
  CloseDate < TODAY()
)

Error: "Close Date cannot be in the past."

6. Close Date must be at least 7 days from today on create

AND(
  ISNEW(),
  CloseDate < TODAY() + 7
)

Error: "Close Date must be at least 7 days out."

7. Birth date must be in the past

AND(
  NOT(ISBLANK(Birthdate)),
  Birthdate > TODAY()
)

Error: "Birth date cannot be in the future."

8. End Date must be after Start Date

AND(
  NOT(ISBLANK(End_Date__c)),
  NOT(ISBLANK(Start_Date__c)),
  End_Date__c < Start_Date__c
)

Error: "End Date must be on or after Start Date."

Money / amounts (Examples 9–11)

9. Discount can't exceed 50%

AND(
  NOT(ISBLANK(Discount__c)),
  Discount__c > 0.5
)

Error: "Discount cannot exceed 50%."

10. Opportunity Amount required for Closed Won

AND(
  ISPICKVAL(StageName, 'Closed Won'),
  OR(ISBLANK(Amount), Amount <= 0)
)

Error: "Amount is required and must be positive when Stage is Closed Won."

11. Annual Revenue must be positive

AND(
  NOT(ISBLANK(AnnualRevenue)),
  AnnualRevenue < 0
)

Error: "Annual Revenue cannot be negative."

Status transitions (Examples 12–14)

12. Can't move Stage backward from Closed Won

AND(
  ISCHANGED(StageName),
  TEXT(PRIORVALUE(StageName)) = 'Closed Won',
  TEXT(StageName) != 'Closed Won'
)

Error: "Once Stage is Closed Won, it cannot be moved back."

13. Closed Lost requires a reason

AND(
  ISPICKVAL(StageName, 'Closed Lost'),
  ISBLANK(TEXT(Loss_Reason__c))
)

Error: "Loss Reason is required when Stage is Closed Lost."

14. Case can't be Closed without resolution notes

AND(
  ISPICKVAL(Status, 'Closed'),
  ISBLANK(Resolution_Notes__c)
)

Error: "Resolution Notes are required to close a Case."

Cross-object (Examples 15–17)

15. Opportunity Amount can't exceed Account's annual revenue

AND(
  NOT(ISBLANK(Amount)),
  NOT(ISBLANK(Account.AnnualRevenue)),
  Amount > Account.AnnualRevenue
)

Error: "Opportunity Amount cannot exceed the Account's Annual Revenue."

16. Contact's email domain must match account's website

AND(
  NOT(ISBLANK(Email)),
  NOT(ISBLANK(Account.Website)),
  NOT(CONTAINS(Email,
    SUBSTITUTE(SUBSTITUTE(Account.Website, 'http://', ''), 'https://', '')))
)

Error: "Contact's Email domain should match the Account's Website."

17. Quote line item count limit per opportunity (workaround using rollup)

AND(
  NOT(ISBLANK(Opportunity.Total_Quote_Lines__c)),
  Opportunity.Total_Quote_Lines__c >= 50
)

Error: "Cannot add more than 50 quote line items per Opportunity."

Record-type specific (Examples 18–20)

18. SLA fields required for Premium Support cases only

AND(
  RecordType.DeveloperName = 'Premium_Support',
  OR(ISBLANK(TEXT(SLA_Tier__c)), ISBLANK(SLA_Response_Time__c))
)

Error: "SLA Tier and Response Time are required for Premium Support cases."

19. B2C accounts must have Person Account fields populated

AND(
  RecordType.DeveloperName = 'Person_Account',
  OR(ISBLANK(FirstName), ISBLANK(LastName))
)

Error: "First and Last Name are required for Person Accounts."

20. Internal cases can't have customer-facing fields filled

AND(
  RecordType.DeveloperName = 'Internal_Issue',
  NOT(ISBLANK(Customer_Communication__c))
)

Error: "Customer-facing fields are not allowed on Internal Issues."

20 examples categorized by type

Error message best practices

The error message is half the rule. A bad message creates a support ticket; a good one teaches the user.

Bad: "Invalid input." Better: "Email cannot be blank." Best: "Email is required for Customers. Please add a valid email like jane@example.com."

The pattern: what's wrong + why + how to fix.

Other guidelines:

  • Address the user, not the system. "You must fill in..." not "System requires..."
  • Suggest a fix, not just the rule. "Use format (555) 123-4567" beats "Phone must match regex."
  • Locate the message at the relevant field. Don't dump everything at the top of the page.
  • Localize. If your org is multi-language, build messages with $Label.X references where possible.
  • Don't expose sensitive logic. "Discount > 50% requires VP approval" is fine; "VP IDs are 005xxx" is a leak.

The patterns that bite

A short list of validation-rule edge cases that catch new admins.

Pattern 1: ISCHANGED + ISNEW behavior

ISCHANGED(field) returns TRUE on insert (the value "changed" from null). If you want to validate only on edits, combine: AND(NOT(ISNEW()), ISCHANGED(field)).

Pattern 2: PRIORVALUE in test classes

PRIORVALUE returns null in some tests. If your rule depends on it, build proper Apex test class coverage that performs an update operation, not just an insert.

Pattern 3: Picklist comparisons

Always wrap picklist values in ISPICKVAL() or TEXT(). Direct equality (StageName = 'Closed Won') sometimes works in formulas but can misbehave with multi-currency or translated values.

Pattern 4: Cross-object null checks

A cross-object formula like Account.AnnualRevenue > 1000000 returns null (treated as false) when the parent isn't set. Always include NOT(ISBLANK(Account.AnnualRevenue)) first.

Pattern 5: Mass transfer skips validation

Salesforce's "Mass Transfer Records" tool skips validation rules. So does the Apex Database.update(records, false) flavor with allOrNothing=false. So do most data loaders. If your validation rule must hold even for mass operations, also enforce in Apex / a record-triggered Flow.

Pattern 6: Record-Triggered Flow can be a better fit

In 2026, complex validation often goes in a record-triggered Flow instead — easier to debug, supports multi-step logic, can call Apex sub-flows. Reserve validation rules for simple field-level invariants.

The five gotchas, with the fix for each

When NOT to use a validation rule

  • Defaulting a field value. Use a formula field, page-layout default, or before-save Flow.
  • Calculating a field from other fields. Use a formula field or Apex.
  • Multi-step business logic. Use a Flow.
  • Workflow-style "if X then send Y" rules. Validation rules block — they don't side-effect.
  • Anything that needs to be skippable by some users. Use a permission-aware Flow that branches on user attributes.

The right validation rule is short, declarative, and "this combination is not allowed" in shape. Anything longer than ~10 lines of formula is a smell.

How Agentforce interacts with validation rules

When an agent calls an Apex Action that updates a record, validation rules fire. The agent's request fails if the rule blocks save — and the agent has to handle that error path, often by asking the user for clarification.

Two implications:

  1. Test agent flows with realistic data. Validation rules that fire only in edge cases will surface the first time an agent hits them in production.
  2. Error messages reach the agent. A clear "Email is required for Customers" message lets the agent ask the user politely. A vague "Invalid input" leaves the agent confused.

Common admin mistakes

  • Stacking 20 rules on one object. They run on every save. Combine where possible.
  • Long, complex formulas with no comments. Future-you will hate present-you.
  • Vague error messages. "Invalid" tells nobody anything.
  • Forgetting that validation rules don't enforce on integrations by default. Add Apex-level enforcement for paths that bypass them.
  • Using LEFT(Phone, 3) = '555' instead of REGEX. REGEX is more readable and handles edge cases.

Frequently asked questions

Can a validation rule fire on a delete? No — validation rules fire on insert and update only. Use a trigger for delete-blocking.

Can I disable a validation rule for a specific user? Yes — add a check like NOT($Permission.Bypass_Validation__c) and grant the custom permission to specific users via Permission Sets.

Do validation rules slow down saves? Negligibly — they're evaluated as formulas. The only time they bite is if you have hundreds firing on bulk DML, where each evaluation adds CPU.

Can validation rules call Apex? No — validation rules are formula-only. For logic that needs Apex, use a record-triggered Flow with an invocable Apex method, or write the logic directly in a Trigger.

How do I see which validation rules fired? Salesforce returns the failure as part of the save error. The standard UI shows the message; in the API, the response includes the rule name. For tracing, enable debug logs on the running user.

If you only adopt one habit: write the error message first. Decide what the user needs to know. Then build the formula that triggers it. The rule that comes out of that order is always better than the one that starts with the formula.

Share this article

Sources

Related dictionary terms

Keep reading