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
@NonNullView on GitHub (pinned to a8ab535614)
Solutions
- Pass the Completable through unchanged instead of wrapping it: drop the unsafeCreate call.
- If you need to hide the concrete identity (so downstream sees a fresh CompletableSource), call source.hide() instead of unsafeCreate(source).
- 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
- Treat unsafeCreate as a bridge for foreign sources only, never for your own Completable.
- Prefer hide() when you need to obscure the concrete Completable identity.
- Add a static type guard in helper code that accepts CompletableSource generically.
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
- unsafeCreate(Maybe) should be upgraded
- unsafeCreate(Single) should be upgraded
- count >= 0 required but it was {}
- count >= 0 required but it was {}
- count >= 0 required but it was {}
AI-assisted analysis of ReactiveX/RxJava@a8ab535614 (2026-08-13).
Data as JSON: /api/errors/bb603c2acbe9eb51.
Report an issue: GitHub.