Instanceof Before Cast

ID

java.instanceof_before_cast

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Java

Tags

CWE:704, reliability

Description

Reports casts to reference types that are not guarded by a preceding instanceof check. Without such a guard, the cast throws ClassCastException at runtime if the expression does not hold a compatible type.

A cast whose operand is a method call is not reported. (String) request.getAttribute(k), (LoggerContext) LogManager.getContext(false), (ClipboardManager) getSystemService(..) and (ThreadPoolExecutor) Executors.newFixedThreadPool(n) are the documented idiom of the API being called: it returns a general type and the caller names the concrete one. An instanceof test needs a variable to test, so the advice cannot be followed at the cast site without first introducing a temporary. A ten-project scan found 1003 of 1634 findings were this shape.

Rationale

When an Object reference is cast to a specific type without first verifying its actual runtime type via instanceof, the cast may fail unexpectedly:

Object o = getElement();
Button b = (Button) o;   // ClassCastException if o is not a Button

This is a common source of runtime errors, especially when dealing with heterogeneous collections, deserialized objects, or framework callbacks that pass Object references.

Remediation

Always guard a reference-type cast with an instanceof check:

Object o = getElement();
if (o instanceof Button) {
    Button b = (Button) o;  // Safe: type verified
    b.click();
}

Primitive casts (e.g. (int) doubleValue) are not affected by this rule since they never throw ClassCastException.

Not reported

A cast that provably cannot throw needs no guard, and is not reported:

  • an upcast — to Object, or to a known supertype of the operand’s declared type ((CharSequence) someString); a redundant cast, where the operand already has the target type;

  • a cast to a type variable, return (S) this;. Type variables are erased at runtime, so the cast is a no-op — and the guard the rule would ask for, this instanceof S, does not compile, so there is no way to act on the finding;

  • a cast on a lambda or a method reference, (ChannelFutureListener) f → {…​}. The cast supplies the target type the functional expression is compiled against; it does not downcast a value;

  • a cast of the null literal, (String) null, used to pick an overload. Casting null never throws, and null instanceof X is always false, so a guard would suppress the very call it protects;

  • a cast of a class literal, (Class<?>) Map.class, which is an upcast.

Test code is also skipped: a failed cast there fails the test rather than reaching production. Matching uses the project-relative path against applicativeCode.excludedPathPatterns — configure additional exclusions in depsdoctor.yml.

© 2026 Xygeni. All rights reserved