Why did a validation rule fail a test I did not touch?
A test tried to insert or update a record, and a validation rule said no. The part after the status code is the error message you wrote on the rule, so the message names the rule's intent even when it does not name the rule.
Your test data is older than the rule. This is why the same deploy can pass in a sandbox that has the rule inactive and fail in production where it is active.
Which tests does a new validation rule break?
- You deployed a new validation rule with metadata that already contains tests inserting records the rule now rejects. Tests across the org break at once, not only the one you touched.
- A required-field rule was added to a standard object, and old tests build an Account or Contact with only a Name.
- The test inserts a User or a record owned by one, and the rule checks a profile, role or field that the test user does not have.
- Sandbox and production disagree. The rule is active in one and inactive in the other.
One Stack Exchange answer says to deactivate the rule in both orgs, deploy, and turn it back on. The poster calls it probably not best practice, and we agree (question 25074). It works in a pinch. It also leaves a window where bad data can get in.
What does the failure look like in a deploy?
A validation rule on Account with the formula ISBLANK(Phone) and a test that inserts new Account(Name = 'Acme Test'), validated with a check-only deploy:
AccountSeedTest.insertsAccount
System.DmlException: Insert failed. First exception on row 0; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, Phone is required on every account.: []
Class.AccountSeedTest.insertsAccount: line 4, column 1
The text before : [] is the rule's error message. Search Setup > Object Manager > Account > Validation Rules for that wording to find the rule.
How do I fix it in Setup?
- Copy the error message text from Setup > Deployment Status > View Details.
- Find the rule: Object Manager, pick the object, Validation Rules. Open it and read the formula.
- Update the test to create valid data. In the example, add
Phone = '555-0100'. Build the records in one shared test data factory class so the next rule only needs one fix. - If the rule only applies to people and not to automation, add a bypass condition such as
$Permission.Bypass_Validationto the formula and give that custom permission to the test through a permission set assignment. Use this sparingly, since it adds a path around your own rule. - Run the test in the sandbox with the rule active before you validate again.
How do I fix it with the CLI?
sf apex run test --class-names AccountSeedTest --result-format human --wait 10 -o <sandbox-alias>
sf project deploy start --dry-run --source-dir force-app --test-level RunSpecifiedTests --tests AccountSeedTest -o <target-alias>
How do I roll out a validation rule without breaking tests?
Treat a new validation rule as a change to every test that touches the object. Before you deploy the rule, search your Apex for insert and new Account( on that object. Keep test records in a factory so there is one place to update. Activate the rule in the sandbox first and run all local tests there, so you find the broken ones before production does.
Salesforce recommends that tests create their own data (Apex Developer Guide). That helps here, because your factory is also the single place the rules get respected.
Clientell AI lists the validation rules related to a proposed change and runs the covering tests before you approve. See AI Salesforce deployments. The validation rule glossary entry explains how rules evaluate.
Other test-time failures: coverage below 75%, assertion failed, trigger exception, callout in a test.
Questions about FIELD_CUSTOM_VALIDATION_EXCEPTION
Why did this start after I only added a validation rule?
Because tests run real DML. A test that inserted a record yesterday inserts the same record today, and the new rule now rejects it. Every test that touches the object is a candidate to break.
Does System.runAs bypass validation rules?
No. runAs changes the running user for sharing and record access. A validation rule still fires unless the formula itself checks the user, profile or a custom permission.
Is it safe to deactivate the rule during the deploy?
It works, but it opens a gap. Records saved while the rule is off skip it. If you do it, schedule the window, do it in both orgs and turn the rule back on straight after.
The error says FIELD_CUSTOM_VALIDATION_EXCEPTION but I cannot find the rule.
Search by the message text. Validation rules on a related object can also fire, and so can rules from managed packages. In the debug log, filter for VALIDATION_RULE events to see the one that ran.