Diagnosing Groovy @CompileStatic Compilation Errors
Learn how to diagnose and fix Groovy @CompileStatic compilation errors caused by dynamic calls, Groovy Truth, safe‑navigation, and delegate/category transformations.
18 Jan 2026, 18:09 UTC

Recognizable Condition
When a Groovy class carries the @CompileStatic annotation, the build may stop with errors such as:
Cannot find matching method ...Unable to resolve property ...GroovyTruth conversion not possible for type ...
Cause and Diagnostic Table
| Cause | What to look for in the source |
|---|---|
| Dynamic dispatch (methodMissing / propertyMissing) | Calls where the target variable is typed as Object or def and the method name is not known at compile time. |
| Groovy Truth usage | Conditions like if (list) or while (map) where the compiler cannot infer a boolean conversion for the static type. |
| Safe‑navigation on unknown type | Expressions such as obj?.method() where obj is Object or def and the actual runtime class is not statically known. |
| @Delegate or @Category introducing invisible methods | Fields annotated with @Delegate or classes using @Category that add methods which the static type checker cannot see. |
Ordered Checks
- Remove
@CompileStatictemporarily from the class (or method) and re‑run the build. If the error disappears, the problem is static‑checking related. - Inspect each problematic line indicated by the compiler message. Determine whether the call uses a variable of type
Object,def, or an unresolved generic type. - Check for Groovy Truth expressions: look for conditions that rely on the truthiness of collections, maps, or strings without an explicit boolean conversion.
- Verify safe‑navigation usage: ensure the left‑hand side has a known static type or add an explicit cast.
- Examine any
@Delegateor@Categoryannotations on the class or its fields; see if the introduced methods are needed in the static context.
Fixes Tied to Findings
Dynamic dispatch
Replace the dynamic call with a strongly typed invocation. Example:
// Before
Object service = lookupService();
service?.performAction(); // error: unable to resolve method performAction
// After
def service = lookupService() as MyServiceInterface;
service.performAction(); // now compile‑time known
If the exact type cannot be known, extract the call into a separate method annotated with @CompileStatic(SKIP) (available in Groovy 3.0+) to isolate the dynamic part.
Groovy Truth
Make the boolean conversion explicit:
// Before
if (items) { ... }
// After
if (items != null && !items.isEmpty()) { ... }
// or
if (items.size() > 0) { ... }
Safe‑navigation on unknown type
Either cast the variable or replace safe‑navigation with a null‑check and typed call:
// Before
Object maybeNode = getNode();
maybeNode?.getValue();
// After
if (maybeNode instanceof Node) {
Node n = (Node) maybeNode;
def val = n.getValue();
}
@Delegate / @Category
If the delegated or category methods are required under static checking, add an explicit interface or delegate method:
@Delegate
private Helper helper;
// Provide a wrapper method visible to the static checker
public void doWork() {
helper.doWork();
}
Alternatively, move the static‑incompatible code to a method marked @CompileStatic(SKIP).
Escalation Criteria
- If after applying the above fixes the error persists and the offending line involves a third‑party library whose source cannot be changed, consider opening an issue with the library maintainer or wrapping the call in a
@CompileStatic(SKIP)block. - When the class contains many dynamic features that would require extensive refactoring, evaluate whether the performance benefits of
@CompileStaticoutweigh the maintenance cost; you may decide to keep the class dynamic and rely on thorough unit tests. - If the build fails on a CI server but passes locally due to differing Groovy versions, verify the Groovy version used in the build (e.g.,
./gradlew -properties | grep groovyVersion) and align environments.
By following the ordered checks and applying the targeted fixes, most @CompileStatic compilation errors can be resolved without disabling the annotation globally.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.