# Salesforce validation rules for opportunities: which fields to require at which stage

https://salesbond.app/blog/salesforce-validation-rules-opportunity-required-fields/
Published: 2026-10-20 · Updated: 2026-10-20

A Salesforce validation rule blocks saving an opportunity when its formula returns true and shows the rep the error message you wrote. So require only what a stage really needs (an Amount from Qualification, a Close Reason on Closed Lost), write one rule per field with a message that says what to do, and check weekly for the placeholder values reps type to get past it. Below is the list we would hand a sales manager who has admin rights, or an admin with a sales manager asking.

## Validation rule vs required field vs Path

Three Salesforce features look like they do the same job. Reps feel the difference on the first save.

A required field on the page layout is required always, at every stage, on every record type that uses the layout. Make Amount required that way and a rep creating a deal after a first call has to invent a number, which then sits in the forecast for weeks.

Sales Path shows guidance and key fields per stage, but on its own it doesn’t stop a save: Path tells, it doesn’t gate. What the guidance should say is in [Sales Path guidance per stage](https://salesbond.app/blog/salesforce-sales-path-guidance-per-stage/).

A validation rule is the only one of the three that can say “at this stage, this field, or no save”. That is the question a sales manager asks, so the rest of this article is about rules. Which fields to *show* per stage is covered in [Dynamic Forms by stage](https://salesbond.app/blog/salesforce-dynamic-forms-stage-fields/).

Creating a rule takes a minute. In Setup, open Object Manager, pick Opportunity, then Validation Rules and New. Give the rule a name, write the error condition formula (it describes the situation you want to stop, not what good data looks like), type the error message, set Error Location to the field, click Check Syntax and save with Active ticked ( [Trailhead: get started with validation rules](https://trailhead.salesforce.com/content/learn/modules/validation-rules/get-started-with-validation-rules)).

## Opportunity validation rules for each stage

Start from the exit criteria you already agreed with the team ( [how to write them for Salesforce stages](https://salesbond.app/blog/salesforce-opportunity-stage-exit-criteria/)). A rule should enforce a criterion someone already said out loud, not spring a new one. Each rule below covers one requirement, named with the object prefix and a running number, the way Trailhead’s best-practice unit does it: one scenario per rule, an error code in the message, and the error placed on the field so the rep gets a link straight to it ( [Trailhead: validation rule best practices](https://trailhead.salesforce.com/content/learn/modules/validation-rules/implement-best-practices)).

| Stage the deal enters | Field that must be filled | Rule name | Error message, on the field |
| --- | --- | --- | --- |
| Qualification or later | Amount | OPP001_Amount_From_Qualification | When the stage is Qualification or higher, you must enter an amount. [OPP001] |
| Qualification or later | Next Step | OPP002_NextStep_From_Qualification | From Qualification on, Next Step needs the next action and its date. [OPP002] |
| Proposal/Price Quote or later | Decision Date (custom) | OPP003_DecisionDate_From_Proposal | Enter the date the buyer said they will decide before moving to Proposal. [OPP003] |
| Negotiation/Review or later | Competitor (custom) | OPP004_Competitor_From_Negotiation | Negotiation needs the competitor, or “None” if the buyer confirmed there isn’t one. [OPP004] |
| Closed Won | Amount greater than zero | OPP005_Amount_On_Won | A won deal needs the final amount, not a placeholder. [OPP005] |
| Closed Lost | Close Reason (custom picklist) | OPP006_CloseReason_On_Lost | Pick a Close Reason before closing as Lost. [OPP006] |

Six rules. The first message is Trailhead’s own example almost word for word: “When the stage is Qualification or higher, you must enter an amount. [OPP003]”. We renumbered because our table starts at one.

What isn’t in the table matters too. Close Date is already required on every opportunity, so it needs no rule ( [Opportunity object reference](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_opportunity.htm)). Probability is filled from the stage automatically. Lead Source, Type, Description: useful, never worth a blocked save. Our test for a new row: would you send a deal back a stage in pipeline review for this blank? If not, don’t block the save for it.

“Or later” is the part people get wrong. Stage is a picklist, so there is no greater-than; you rank the stages yourself with CASE, the same way Salesforce’s own sample opportunity rules do ( [Examples of validation rules: opportunity management](https://developer.salesforce.com/docs/atlas.en-us.usefulValidationRules.meta/usefulValidationRules/fields_useful_validation_formulas_oppty_mgmt.htm)). This is OPP001 with the default sales process stages. Put in your own picklist values:

```
AND(
  CASE(StageName,
    "Prospecting", 1,
    "Qualification", 2,
    "Needs Analysis", 3,
    "Value Proposition", 4,
    "Id. Decision Makers", 5,
    "Perception Analysis", 6,
    "Proposal/Price Quote", 7,
    "Negotiation/Review", 8,
    "Closed Won", 9,
    0) >= 2,
  ISBLANK(Amount)
)
```

The threshold is what makes it work. A rule that checks ISPICKVAL for one stage misses the rep who jumps from Prospecting straight to Proposal; “>= 2” catches every stage past Qualification, skipped or not. Closed Lost is left out on purpose, so it falls to 0 and a dead deal with no amount can still be closed. OPP002 to OPP004 use the same CASE with a different threshold (7 for Proposal, 8 for Negotiation). Yes the stage list now lives in several formulas. We accept that over one giant rule.

## Closed Lost needs a reason

The rule everyone agrees with and almost nobody has:

```
AND(
  ISPICKVAL(StageName, "Closed Lost"),
  ISBLANK(TEXT(Close_Reason__c))
)
```

Trailhead’s hands-on project builds exactly this check, ISPICKVAL on the stage plus ISBLANK on the reason ( [Trailhead: create validation rules](https://trailhead.salesforce.com/content/learn/projects/customize-a-salesforce-object/create-validation-rules-1)). Ours wraps the reason in TEXT() because Close_Reason__c here is a picklist, and TEXT is how a validation rule reads a picklist value as text.

Two decisions make it useful instead of annoying. Keep the picklist to six to eight values a rep can pick without thinking: Price, Chose competitor, No decision, Timing, Lost contact, Not a fit. And if you add “Other”, add a second rule requiring a text field with it, or Other becomes the answer to everything within a month. Won’t read that text? Drop Other. A reason you never read is a field you shouldn’t require.

## One rule per requirement, not one per stage

It is tempting to build one Qualification rule that checks Amount and Next Step together. Don’t. The rep sees one error and can’t tell which field it means, the error can’t sit on two fields, and when Next Step later moves to Proposal you are editing a formula that also guards Amount. Trailhead uses this very example to argue for splitting, and we agree.

The cost is a longer list in Setup, paid by the admin once. A combined rule costs every rep on every save. Name rules as in the table and the Setup list reads like the table.

## Error messages reps can act on

A rep reads a validation message at exactly one moment: when it has just stopped them.

Every message in the table has the same shape: condition (“When the stage is Qualification or higher”), action (“you must enter an amount”), code in brackets. The condition explains why a save that worked yesterday fails today. The action says what to do. The code gives the admin something to search for when a rep forwards a screenshot with “this thing again”.

![One validation error message split into condition, action and code, with an arrow to the Amount field it sits under](https://salesbond.app/wp-content/uploads/2026/10/salesforce-validation-rules-opportunity-required-fields-2.png)

Put the error on the field, not at the top of the page. In our experience reps read a top-of-page error as “Salesforce is broken” and a field error as “fill this in”. And never write the message as a reproach. “Amount missing” is a fact. “You forgot the amount again” is a management conversation and it doesn’t belong in a formula.

## Don’t break old records

A new rule applies to every save, including a save of a deal created two years ago under different rules. The week you switch on OPP001, a rep fixing a typo on an old Negotiation deal hits “you must enter an amount” on a deal they didn’t create. That is how rules get switched off.

Trailhead names three functions for aiming a rule at the change you care about: ISCHANGED, ISNEW and PRIORVALUE. We start every rule in the table with one extra line:

```
OR(ISNEW(), ISCHANGED(StageName)),
```

Added as the first condition inside AND(), it makes the rule fire only when a deal is created or its stage moves. An old deal can be edited in place and gets checked at its next stage change. ISNEW() is there because a field doesn’t count as changed while the record is being created, so ISCHANGED alone would let a brand-new deal be saved at Qualification with no amount.

PRIORVALUE is for locking. Trailhead’s example is the one every sales team eventually wants, stopping anyone from moving an opportunity out of Closed Won:

```
AND(
  ISPICKVAL(PRIORVALUE(StageName), "Closed Won"),
  NOT(ISPICKVAL(StageName, "Closed Won"))
)
```

Add a profile exception for the admin, or the rule will also stop you from from fixing a genuinely wrong close.

One more thing before you trust a test. Custom validation rules run after before-save record-triggered flows and before triggers, and before after-save flows ( [Salesforce Developers: Triggers and Order of Execution](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_triggers_order_of_execution.htm)). So a before-save flow that fills a field satisfies your rule before the rep ever sees it. That’s fine when the flow is honest and misleading when it writes defaults. Test rules in a sandbox with your flows switched on, not in a clean org.

## The “n/a” problem: fake values and how to spot them

A validation rule that only checks for blanks gets answered with placeholders. Switch on OPP002 and within a week Next Step will contain “tbd”, “n/a”, “follow up” and a lone full stop. Switch on OPP001 and Amount will be 1. The rule did its job, the field has a value, and the forecast is worse than before, because now the blank looks filled.

We don’t think this is a rep problem. It is the predictable answer to a gate nobody reads behind. Two things reduce it; nothing removes it.

The first is a narrower rule, because a formula can see more than blanks. Keep the stage check from OPP002 and replace its ISBLANK(NextStep) with:

```
OR(
    ISBLANK(NextStep),
    LEN(NextStep) < 10,
    CONTAINS(LOWER(NextStep), "tbd"),
    CONTAINS(LOWER(NextStep), "n/a")
  )
```

For Amount, use `Amount < 100` (or whatever your smallest real deal is) instead of ISBLANK(Amount). Keep the list of banned strings short. A rule that chases every variant turns into a game, and reps are better at games than admins.

The second is a report you actually look at: open opportunities where Next Step contains “tbd” or Amount is below your floor, grouped by owner. Its a different report from the blank-field one in the Dynamic Forms article, and it catches what the rule lets through. Read it on the same day each week and ask about two deals, not ten. Reps notice the field is being read, usually within a month.

This is also where we should say what we build. SalesBond is a sales management layer on top of the CRM a team already uses; it works with Pipedrive, HubSpot, Salesforce and Zoho CRM. Deal Health checks every open opportunity against more than 20 rules and shows the specific violations on each deal, so the weekly list starts from the exceptions rather than from a filter you maintain. It doesn’t write your validation rules, and it can’t tell an honest Next Step from a plausible one; that is still the review. If you want to see your open opportunities against a rule set this week, [check your CRM with SalesBond](https://salesbond.app/).

## Review the rules every quarter

Rules outlive their reasons. In a quarter a stage gets renamed, a field retired, or a rep finds the value that passes, so book thirty minutes at quarter end. Start with the reps: ask which message they see most and believe them. Then look for teh rule nobody mentions. Either the team has learned it, or nobody reaches that stage any more, and both are worth knowing.

Check that the CASE list in each formula still matches the stage picklist, because a renamed stage silently falls to 0 and the rule stops gating it. Open the fake-value report for the quarter: a string that keeps appearing goes into the rule, while the same two names appearing every week is a coaching conversation, not a formula change. Last, any rule a manager asked you to bypass “just this once” either gets a proper profile condition or gets deleted. A rule with informal exceptions is a rule that isn’t there.

If your team runs on Pipedrive or HubSpot instead, the thinking is the same and the mechanics differ: [required fields in Pipedrive](https://salesbond.app/blog/required-fields-pipedrive/) and [stage required properties in HubSpot](https://salesbond.app/blog/hubspot-stage-required-properties/).
