ReactiveX/RxJava · error · UnsupportedOperationException

The class {} does not support isDisposed

Error message

The class {} does not support isDisposed

What it means

Thrown by the default isDisposed() implementation inherited via the DisposableOnly interface. DisposableOnly extends Disposable but explicitly opts out of implementing isDisposed(), because for many disposable resources the disposed state is either never observable or never queried in practice. Any code that calls isDisposed() on an instance typed only as DisposableOnly/Disposable will hit this UnsupportedOperationException at runtime — the compiler will not warn because the method exists on the interface.

Source

Thrown at src/main/java/io/reactivex/rxjava4/internal/disposables/DisposableOnly.java:28

 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
 * the License for the specific language governing permissions and limitations under the License.
 */

package io.reactivex.rxjava4.internal.disposables;

import io.reactivex.rxjava4.disposables.Disposable;

/**
 * An extension to {@link Disposable} that allows not
 * implementing the {@link Disposable#isDisposed()} as it
 * is practically never needed or cannot be observed anyways.
 * @since 4.0.0
 */
public interface DisposableOnly extends Disposable {

    @Override
    default boolean isDisposed() {
        throw new UnsupportedOperationException("The class " + this.getClass() + " does not support isDisposed");
    }
}

View on GitHub (pinned to a8ab535614)

Solutions

  1. Do not call isDisposed() on DisposableOnly instances; track disposal yourself (e.g. via a boolean flag set in dispose()).
  2. Narrow the type so callers cannot reach isDisposed(), or override isDisposed() in the implementing class if the state is actually observable.
  3. In shared helpers, guard with an instanceof/type check (see defense) before invoking isDisposed().
  4. If you genuinely need disposed-state observation, use a full Disposable implementation (e.g. via a ref-counted or AtomicBoolean-based disposable) instead of DisposableOnly.

Example fix

// before
DisposableOnly d = createResource();
if (d.isDisposed()) { ... } // throws UnsupportedOperationException

// after
DisposableOnly d = createResource();
// track disposal yourself; never call isDisposed() on DisposableOnly
Defensive patterns

Strategy: type-guard

Validate before calling

boolean safeIsDisposed(Disposable d) {
    if (d instanceof DisposableOnly && !overridesIsDisposed(d)) {
        return false; // state not observable; assume not disposed or track externally
    }
    return d.isDisposed();
}

Type guard

boolean isFullyObservable(Disposable d) {
    // DisposableOnly opts out of isDisposed by default; treat such instances as non-queryable.
    return !(d instanceof DisposableOnly);
}

Prevention

When it happens

Trigger: Calling isDisposed() on an object whose static or declared type is DisposableOnly (or a class implementing it without overriding isDisposed). Common when a resource is stored in a Disposable-typed field or passed to a helper that defensively calls isDisposed().

Common situations: Generic resource-tracking utilities that call isDisposed() on every Disposable; testing helpers that assert disposed state; migrating from RxJava 2/3 where isDisposed() was always implemented; using CompositeDisposable-like bookkeeping that probes state.

Related errors


AI-assisted analysis of ReactiveX/RxJava@a8ab535614 (2026-08-13). Data as JSON: /api/errors/c050f781ac73b727. Report an issue: GitHub.