Skip to content

ERROR_IN_CUSTOM_PROVIDER

Googler edited this page Mar 11, 2021 · 3 revisions

ERROR_IN_CUSTOM_PROVIDER

Summary

Guice will throw a ProvisionException with an ERROR_IN_CUSTOM_PROVIDER error code when a provider in Guice throws a runtime exception.

Example:

final class FooModule extends AbstractModule {

  @Override
  protected void configure() {
    bind(Bar.class).toProvider(BarProvider.class);
  }

  @Provides
  Foo provideFoo(Bar bar) {
    // An ERROR_IN_CUSTOM_PROVIDER error will be reported if this precondition
    // check fails.
    Preconditions.checkState(bar.hasFoo());
    return bar.getFoo();
  }
}

final class BarProvider implements Provider<Bar> {
  @Override
  public Bar get() {
    // An ERROR_IN_CUSTOM_PROVIDER error will be reported if this method
    // throws an exception
    ...
  }
}

Causes

Unexpected exception thrown from provider

ERROR_IN_CUSTOM_PROVIDER error occurs when Guice calls application code (e.g a @Provides method) to create an object and that code throws an exception. To fix the error, examine and address the associated underlying cause of the error (the cause of the ProvisionException) so that Guice can successfully create the required objects. For example, you can handle the exception by catching it and return a fallback object instead of letting Guice handle the exception.

Expected ProvisionException

Sometimes it is reasonable to have some ERROR_IN_CUSTOM_PROVIDER errors if those errors are caused by exceptions that are expected to occur at runtime. For example, a binding that is derived from user input can fail if the input is invalid. However, to make the root cause of the exception clearer, you should consider throwing the exception before or after triggering Guice provisioning so that the root cause exception is not wrapped inside a ProvisionException.

Examples:

final class FooModule extends AbstractModule {
  @Provides
  Foo provideFoo(FooRequest request) {
    // FooFactory throws an exception if request is invalid. The exception will
    // cause Guice to throw a ProvisionException with an
    // ERROR_IN_CUSTOM_PROVIDER error, which may obscure the root cause of the
    // exception.
    return FooFactory.create(request);
  }
}

final class RequestHandler {
  private final Provider<Foo> fooProvider;

  @Inject RequestHandler(Provider<Foo> fooProvider) {
    this.fooProvider = fooProvider;
  }

  public FooResponse handleRequest() {
    // Guice will throw a ProvisionException if request is invalid.
    return handleFoo(fooProvider.get());
  }
}

Validate input before Guice provisioning

final class RequestHandler {
  private final Provider<Foo> fooProvider;

  @Inject RequestHandler(Provider<Foo> fooProvider) {
    this.fooProvider = fooProvider;
  }

  public FooResponse handleRequest(FooRequest request) {
    // Validate the request and throw BadRequestException if request has invalid
    // input, so the call to fooProvider.get() is guaranteed to succeed.
    if (!isValid(request)) {
      throw new BadRequestException("invalid request");
    }
    Foo foo = fooProvider.get();
    return handleFoo(foo);
  }
}

final class FooModule extends AbstractModule {
  @Provides
  Foo provideFoo(FooRequest request) {
    // Since request is validated before provideFoo is called, FooFactory.create
    // will not throw an exception.
    return FooFactory.create(request);
  }
}

Alternatively, perform the validation after Guice provisioning

final class FooModule extends AbstractModule {
  @Provides
  Foo provideFoo(FooRequest request) {
    // FooFactory never throws exception and request validation is deferred
    // until Foo.isValid is called.
    return FooFactory.create(request);
  }
}

final class RequestHandler {
  private final Provider<Foo> fooProvider;

  @Inject
  RequestHandler(Provider<Foo> fooProvider) {
    this.fooProvider = fooProvider;
  }

  public FooResponse handleRequest(FooRequest request) {
    Foo foo = fooProvider.get();
    // fooProvider never throws exception but can return Foo instances that
    // returns false when isValid is called.
    if (!foo.isValid()) {
      throw new BadRequestException("invalid request");
    }
    return handleFoo(foo);
  }
}
Clone this wiki locally