Netflix/Hystrix · warning · UnsupportedOperationException

AsyncResult is just a stub and cannot be used as complete im

Error message

AsyncResult is just a stub and cannot be used as complete implementation of Future

What it means

AsyncResult is an abstract stub meant only as a declaration vehicle for async Hystrix command methods: Javanica intercepts the method, invokes your invoke() implementation on a Hystrix thread, and manages the real Future itself. The Future interface methods are implemented to always throw UnsupportedOperationException so nobody treats the AsyncResult instance as a working Future. This error is cancel(boolean).

Source

Thrown at hystrix-contrib/hystrix-javanica/src/main/java/com/netflix/hystrix/contrib/javanica/command/AsyncResult.java:34

package com.netflix.hystrix.contrib.javanica.command;

import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * Fake implementation of {@link Future}. Can be used for method signatures
 * which are declared with a Future return type for asynchronous execution.
 * Provides abstract {@link #invoke()} method to wrap some logic for an asynchronous call.
 *
 * @param <T> the type of result
 */
public abstract class AsyncResult<T> implements Future<T>, ClosureCommand<T> {

    private static final String ERROR_MSG = "AsyncResult is just a stub and cannot be used as complete implementation of Future";

    @Override
    public boolean cancel(boolean mayInterruptIfRunning) throws UnsupportedOperationException {
        throw new UnsupportedOperationException(ERROR_MSG);
    }

    @Override
    public boolean isCancelled() throws UnsupportedOperationException {
        throw new UnsupportedOperationException(ERROR_MSG);
    }

    @Override
    public boolean isDone() throws UnsupportedOperationException {
        throw new UnsupportedOperationException(ERROR_MSG);
    }

    @Override
    public T get() throws UnsupportedOperationException {
        throw new UnsupportedOperationException(ERROR_MSG);
    }

    @Override

View on GitHub (pinned to 5ce3bc58c3)

Solutions

  1. Remove code that invokes cancel/cancel-related Future methods on AsyncResult; cancellation is not supported by this pattern.
  2. If you need a cancellable Future, return a real Future from the command method (or use queue() on a programmatic HystrixCommand) instead of AsyncResult.
  3. Keep AsyncResult instances confined to the annotated method's return; treat the object as opaque.

Example fix

// before
AsyncResult<String> ar = userService.getName(id); // if directly exposed
ar.cancel(true);

// after
// let Javanica manage the Future; to use it, consume the method's returned Future:
Future<String> f = userService.getName(id);  // proxy returns a real Future
String name = f.get(2, TimeUnit.SECONDS);
Defensive patterns

Strategy: type-guard

Type guard

static boolean isAsyncResultStub(Future<?> f) {
    return f instanceof com.netflix.hystrix.contrib.javanica.command.AsyncResult;
}

Try / catch

try { f.cancel(true); } catch (UnsupportedOperationException e) { if (f instanceof AsyncResult) { /* stub by design — skip */ } else throw e; }

Prevention

When it happens

Trigger: Directly calling cancel() on an AsyncResult instance, e.g. new AsyncResult<String>(){...}.cancel(true), or handing the AsyncResult object to code that manages Futures (timeout watchdogs, ExecutorService machinery, CompletableFuture adapters).

Common situations: Developers unfamiliar with the pattern trying to use the returned AsyncResult as a real Future; passing the collapser/command method body's return object into generic async orchestration code; calling cancel to abort a timed-out call.

Related errors


AI-assisted analysis of Netflix/Hystrix@5ce3bc58c3 (2026-08-14). Data as JSON: /api/errors/c61f1223dedea58f. Report an issue: GitHub.