A failed Salesforce deployment usually gives you a component name, a line number that may or may not correspond to your file, and a message written for the platform rather than for you. Nearly all of them fall into five families.
1. Code coverage below 75%
The message is some variant of Code coverage requirement not met, often with a count of classes below the threshold. Two things trip people up.
First, the 75% is org-wide for production deployments, not per class — but any individual trigger must have some coverage. Second, coverage is calculated from the tests that actually ran. Deploying with RunSpecifiedTests and naming three test classes will compute coverage from those three alone, which is why a deployment can fail on coverage even though the org sits comfortably above the line.
If a deployment fails on coverage unexpectedly, check the test level before you go writing tests.
2. Missing dependencies
In field: field — no CustomField named Account.Region__c found means the package references something the target does not have. This is the single most common reason a hand-assembled deployment fails, and it is a symptom of assembling packages by hand rather than from a diff.
A record type references a picklist value. A layout references a field. A permission set references an Apex class. A Flow references all three. Miss any one and the whole deployment rolls back.
The reliable fix is to stop choosing components from memory. If your package is built from an actual comparison of source and target, the missing piece shows up in the diff as “new” before you deploy.
3. Apex test failures
Distinct from coverage: the tests ran and something asserted false. The two recurring culprits are tests that depend on org data rather than creating their own (they pass in the sandbox that has the data and fail in the org that doesn’t), and tests that depend on the running user’s permissions.
Validation runs matter here. A check-only deployment executes the same tests without committing anything, so you find out in the sandbox rather than in the production deployment window.
4. Mixed DML and other runtime rules
MIXED_DML_OPERATION during a test means setup objects (User, PermissionSet assignments, Group members) and non-setup objects were written in one transaction. It almost always surfaces during deployment rather than development, because the test only creates a User when the deploying context lacks the data it usually relies on.
5. Things the Metadata API simply will not do
Some failures are not bugs. Picklist value deletions, certain field type changes, and anything requiring data migration behind it will be refused. Master-detail conversions, reducing a field’s length below existing data, changing a field’s API name — these need a manual path, and no deployment tool changes that.
Reading the actual failure faster
The Setup deployment status screen shows failures one component at a time, which is a poor way to understand a 40-component rollback. What you usually want is the grouped view: how many failures, of what kind, on which components — with compile errors separated from test failures separated from coverage.
In orgadmin.ai, a failed run is summarised that way, and in the Development Studio those same compile errors and test failures are fed back to the AI assistant with their line numbers, so the next iteration is written against the real error rather than a guess about it.
One honest limitation
There is no automatic rollback. A failed Metadata API deployment rolls back on its own (that is the platform’s behaviour, not a feature), but a successful deployment you later regret has to be reverted by deploying the previous state — which means you need to have kept it. That is the strongest argument for git-backed CI/CD, and it is a genuine gap here.