ReactiveX/RxJava · error · IllegalArgumentException

Use of unsafeCreate(Completable)!

Error message

Use of unsafeCreate(Completable)!

What it means

Thrown by Completable.unsafeCreate when the passed source is already a Completable instance. unsafeCreate exists to bridge foreign CompletableSource implementations; wrapping a real Completable is redundant (you already have the target type) and is almost always a 1.x-to-3.x/4.x porting remnant. The guard is an explicit instanceof check that fails fast at assembly time.

Source

Thrown at src/main/java/io/reactivex/rxjava4/core/Completable.java:427

     * <p>
     * <img width="640" height="260" src="https://raw.github.com/wiki/ReactiveX/RxJava/images/rx-operators/Completable.unsafeCreate.png" alt="">
     * <dl>
     *  <dt><b>Scheduler:</b></dt>
     *  <dd>{@code unsafeCreate} does not operate by default on a particular {@link Scheduler}.</dd>
     * </dl>
     * @param onSubscribe the callback which will receive the {@link CompletableObserver} instances
     * when the {@code Completable} is subscribed to.
     * @return the new {@code Completable} instance
     * @throws NullPointerException if {@code onSubscribe} is {@code null}
     * @throws IllegalArgumentException if {@code source} is a {@code Completable}
     */
    @CheckReturnValue
    @NonNull
    @SchedulerSupport(SchedulerSupport.NONE)
    public static Completable unsafeCreate(@NonNull CompletableSource onSubscribe) {
        Objects.requireNonNull(onSubscribe, "onSubscribe is null");
        if (onSubscribe instanceof Completable) {
            throw new IllegalArgumentException("Use of unsafeCreate(Completable)!");
        }
        return RxJavaPlugins.onAssembly(new CompletableFromUnsafeSource(onSubscribe));
    }

    /**
     * Defers the subscription to a {@code Completable} instance returned by a supplier.
     * <p>
     * <img width="640" height="298" src="https://raw.github.com/wiki/ReactiveX/RxJava/images/rx-operators/Completable.defer.png" alt="">
     * <dl>
     *  <dt><b>Scheduler:</b></dt>
     *  <dd>{@code defer} does not operate by default on a particular {@link Scheduler}.</dd>
     * </dl>
     * @param supplier the supplier that returns the {@code Completable} that will be subscribed to.
     * @return the new {@code Completable} instance
     * @throws NullPointerException if {@code supplier} is {@code null}
     */
    @CheckReturnValue
    @NonNull

View on GitHub (pinned to a8ab535614)

Solutions

  1. Pass the Completable through unchanged instead of wrapping it: drop the unsafeCreate call.
  2. If you need to hide the concrete identity (so downstream sees a fresh CompletableSource), call source.hide() instead of unsafeCreate(source).
  3. If the argument may legitimately be a foreign CompletableSource, narrow the call site so unsafeCreate only receives non-Completable sources.

Example fix

// before
Completable src = loadCompletable();
Completable wrapped = Completable.unsafeCreate(src);

// after
Completable wrapped = src;
// or, to hide identity:
Completable hidden = src.hide();
Defensive patterns

Strategy: type-guard

Validate before calling

CompletableSource source = loadSource();
if (source instanceof Completable) {
    // unsafeCreate would throw; use directly or hide()
    return;
}

Type guard

static boolean needsUnsafeCreate(CompletableSource s) {
    return s != null && !(s instanceof Completable);
}

Try / catch

try {
    return Completable.unsafeCreate(source);
} catch (IllegalArgumentException e) {
    // source was already a Completable; use it directly
    return source instanceof Completable ? (Completable) source : Completable.error(e);
}

Prevention

When it happens

Trigger: Calling Completable.unsafeCreate(someCompletable) where the argument's runtime type is Completable (not just CompletableSource). Common when a method returns Completable and the caller passes it straight into unsafeCreate.

Common situations: Migrating RxJava 1.x code that used Observable.unsafeCreate patterns; helper utilities that accept a generic source and unconditionally wrap it; generated/builder code that blindly calls unsafeCreate on whatever upstream it receives.

Related errors


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