Apex

Dependent Class Is Invalid and Needs Recompilation: Catch It Before Runtime With Winter '27's Compile Only Invalid Classes

By Rishabh Panwar · Published 27 September 2026 · 5 min read · Intermediate

A deploy goes through cleanly, and then the first user to open a page gets this:

Dependent class is invalid and needs recompilation: Class StDepB : Method does not exist or incorrect signature: void twice(Integer) from the type StDepA

StDepA and StDepB are two small test classes we built for this post. StDepA has one static method, twice():

public class StDepA {
    public static Integer twice(Integer n) { return n * 2; }
}

StDepB depends on it by calling that method:

public class StDepB {
    public static Integer run() { return StDepA.twice(21); }
}

We then renamed the method in StDepA and saved it:

public class StDepA {
    public static Integer doubleIt(Integer n) { return n * 2; }
}

Salesforce saved the change without complaint. StDepB was left calling twice(), which no longer exists, and nothing flagged it until StDepB ran. In a real org, swap in any class that calls a method on another class, such as a controller calling a service or a trigger handler calling a utility.

The deploy didn’t catch it because nothing forced StDepB to compile. Winter ‘27 adds two ways to find these classes before a user does: Compile only invalid classes buttons in Setup and a new Tooling API endpoint, apexCompileResults. We tested both with these two classes and found that two Salesforce documents give opposite answers about whether the buttons reset a class’s IsValid flag.

What “invalid” means

Every Apex class has an IsValid flag. When a class changes, Salesforce marks the classes that depend on it as invalid and recompiles them the next time they run. If the dependency changed in a way the caller can’t compile against, that recompile fails and you get the error above.

The part most developers miss is that IsValid = false doesn’t mean the class is broken. We made a harmless change and the caller was still flagged. Starting again from the original versions of the two classes above, we tracked both with one query:

SELECT Name, IsValid, LastModifiedDate FROM ApexClass WHERE Name LIKE 'StDep%'
StepWhat we didStDepB.IsValid
1Created both classestrue
2Added an unrelated method to StDepAfalse
3Setup → Apex Classes → Compile only invalid classesstill false
4Ran System.debug(StDepB.run()); in Anonymous Apextrue
5Renamed twice to doubleIt in StDepA (the save succeeded)false
6Ran StDepB.run() againruntime error shown above

Two results stand out. Salesforce let us save a change that broke a dependent class, with no warning. And the only thing that reset IsValid was running the class, which is also the moment the error reaches a user.

Salesforce’s two documents disagree

Two official Salesforce pages describe the same feature and give opposite answers about whether the Setup buttons reset IsValid.

Source 1: the Winter ‘27 release note. Reduce Overhead by Recompiling Only Invalid Apex Classes and Triggers says a successful compile through either the Compile only invalid buttons or the apexCompileResults endpoint doesn’t update the class’s isValid field. In its words: “The value remains false.”

Source 2: the Tooling API reference. Retrieve Compilation Results for Invalid Apex with the apexCompileResults Resource, in its Usage section, says a successful compile through the Setup buttons “updates the IsValid field on the corresponding Apex class or trigger to true.” Only the endpoint, it says, leaves the field unchanged.

Our step 3 settles it: after clicking the button, StDepB stayed false, which matches Source 1. The practical consequence: you can’t use IsValid to confirm the button worked. A query for IsValid = false after clicking it returns the same classes as before, so check compile results instead.

The two Winter ‘27 tools

Both need API version 68.0 or later, and the feature is available in Enterprise, Performance, Unlimited and Developer editions.

The buttons. Setup → Apex Classes has Compile only invalid classes, and Setup → Apex Triggers has Compile only invalid triggers. Both limit the work to what Salesforce has flagged, which matters in large orgs where compiling everything is slow enough that teams avoid it.

The endpoint. POST /services/data/v68.0/tooling/apexCompileResults/ takes an empty JSON body, runs synchronously, and needs the Author Apex permission. It returns OK when everything invalid compiles, or PARTIAL_FAILURE with line and column for each class or trigger that doesn’t. Classes that compile cleanly aren’t listed. After our breaking change, StDepB appeared like this:

{
  "name": "StDepB",
  "namespace": "",
  "problems": [
    {
      "column": 49,
      "line": 2,
      "message": "Method does not exist or incorrect signature: void twice(Integer) from the type StDepA"
    }
  ],
  "success": false,
  "warnings": []
}

That’s the same compile error the user saw at runtime, reported before anyone ran the class.

What the first call found

Our first request to the endpoint returned PARTIAL_FAILURE before we had broken anything. A few existing classes in the org referenced objects that weren’t enabled there, so each one failed with Invalid type errors. Nobody had noticed, because nothing had called them.

Expect the same in most long-lived orgs. Run the endpoint once by hand before you automate it, and decide for each failing class whether to fix it, delete it, or exclude it from your pipeline check.

Add it to your pipeline

Run the endpoint straight after every deploy and fail the job if anything doesn’t compile. With the Salesforce CLI and jq:

ORG_JSON=$(sf org display --target-org "$TARGET_ORG" --json)
TOKEN=$(echo "$ORG_JSON" | jq -r '.result.accessToken')
INSTANCE=$(echo "$ORG_JSON" | jq -r '.result.instanceUrl')

RESULT=$(curl -s -X POST "$INSTANCE/services/data/v68.0/tooling/apexCompileResults/" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}')

if [ "$(echo "$RESULT" | jq -r '.status')" != "OK" ]; then
  echo "Apex that no longer compiles:"
  echo "$RESULT" | jq -r '.results[] | "\(.name): \(.problems[0].message) (line \(.problems[0].line))"'
  exit 1
fi

If you have known failures you’ve decided to live with, filter them out by name before the status check so the job only fails on new breakage.

Version bumps are a common trigger for this. Raising a class’s API version can change how it compiles, as the API v67 user mode post shows, and dependents are flagged when you do.

A routine that works

WhenDo
After every deployCall apexCompileResults and fail on PARTIAL_FAILURE
After a major release upgradeRun it by hand and review anything new
Before peak trafficExecute or test the classes you just changed, since running them is what we saw reset IsValid
When IsValid = false appearsCheck the compile results before assuming the class is broken

Winter ‘27 has other Apex changes worth reading next to this one, including larger heap limits and the new Web Console and Developer Console toggles.

Frequently asked questions

What does 'Dependent class is invalid and needs recompilation' mean in Salesforce?

A class your code depends on changed after the calling class was last compiled, and the calling class no longer compiles against it. Salesforce only discovers this when the calling class runs, so the error surfaces at runtime instead of at deploy time.

How do I fix 'Dependent class is invalid and needs recompilation'?

Read the second half of the message: it names the dependent class and the compile error, such as a method that no longer exists. Update that class to match the changed dependency, or restore the method it relies on, then save it.

What does IsValid = false mean on an Apex class?

It means Salesforce has flagged the class for recompilation because something it depends on changed. In our test, adding a new method to a dependency flipped the caller to IsValid = false even though the caller still compiled fine.

Does Compile only invalid classes set IsValid back to true?

Not in our test. After clicking Compile only invalid classes, the dependent class stayed IsValid = false. Running the class did flip it to true. Salesforce's release note matches this, while the Tooling API reference says the buttons set IsValid to true.

What is the apexCompileResults Tooling API endpoint?

A Winter '27 Tooling API resource, available in API version 68.0 and later. You POST an empty JSON body to /services/data/v68.0/tooling/apexCompileResults and it returns OK or PARTIAL_FAILURE, with line-level errors for every invalid class or trigger that fails to compile. It requires the Author Apex permission.

Which Salesforce editions support compiling only invalid Apex classes?

Enterprise, Performance, Unlimited and Developer editions, in Lightning Experience and Salesforce Classic, from API version 68.0 (Winter '27).