lysine-dev/retrofit · error · NullPointerException

gson == null

Error message

gson == null

What it means

Thrown by GsonConverterFactory.create(Gson) as an explicit NullPointerException when a caller passes a null Gson instance. The factory stores the Gson reference for all subsequent request/response conversions, so a null value would NPE much later during conversion; the factory fails fast at construction to surface the misconfiguration at the call site.

Source

Thrown at retrofit-converters/gson/src/main/java/retrofit2/converter/gson/GsonConverterFactory.java:52

 * buffers), you must {@linkplain Retrofit.Builder#addConverterFactory(Converter.Factory) add this
 * instance} last to allow the other converters a chance to see their types.
 */
public final class GsonConverterFactory extends Converter.Factory {
  /**
   * Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
   * decoding from JSON (when no charset is specified by a header) will use UTF-8.
   */
  public static GsonConverterFactory create() {
    return create(new Gson());
  }

  /**
   * Create an instance using {@code gson} for conversion. Encoding to JSON and decoding from JSON
   * (when no charset is specified by a header) will use UTF-8.
   */
  @SuppressWarnings("ConstantConditions") // Guarding public API nullability.
  public static GsonConverterFactory create(Gson gson) {
    if (gson == null) throw new NullPointerException("gson == null");
    return new GsonConverterFactory(gson, false);
  }

  private final Gson gson;
  private final boolean streaming;

  private GsonConverterFactory(Gson gson, boolean streaming) {
    this.gson = gson;
    this.streaming = streaming;
  }

  /**
   * Return a new factory which streams serialization of request messages to bytes on the HTTP thread
   * This is either the calling thread for {@link Call#execute()}, or one of OkHttp's background
   * threads for {@link Call#enqueue}. Response bytes are always converted to message instances on
   * one of OkHttp's background threads.
   */
  public GsonConverterFactory withStreaming() {

View on GitHub (pinned to d0b112dad0)

Solutions

  1. Pass a non-null Gson: use GsonConverterFactory.create() to get a default instance, or GsonConverterFactory.create(new GsonBuilder()....create()).
  2. If using DI, fix the @Provides Gson binding so it never returns null.
  3. Initialize the Gson field before constructing the factory, or mark it final and assign in the constructor.
  4. In tests, pass a real Gson or a properly stubbed non-null mock.

Example fix

// before
Gson gson = maybeConfiguredGson(); // returns null
Retrofit retrofit = new Retrofit.Builder()
    .addConverterFactory(GsonConverterFactory.create(gson))
    .build();

// after
Gson gson = maybeConfiguredGson();
if (gson == null) gson = new Gson();
Retrofit retrofit = new Retrofit.Builder()
    .addConverterFactory(GsonConverterFactory.create(gson))
    .build();
Defensive patterns

Strategy: validation

Validate before calling

// Validate before constructing the factory.
Gson gson = resolveGson();
if (gson == null) {
  throw new IllegalStateException("Gson instance must not be null before building GsonConverterFactory");
}
GsonConverterFactory factory = GsonConverterFactory.create(gson);

Type guard

// Kotlin: use a non-nullable parameter so the compiler rejects null at the call site.
fun converterFactory(gson: Gson): GsonConverterFactory =
    GsonConverterFactory.create(gson)

Try / catch

// Construction-time NPE; catch only if a third-party provider may return null.
GsonConverterFactory factory;
try {
  factory = GsonConverterFactory.create(resolveGson());
} catch (NullPointerException e) {
  if ("gson == null".equals(e.getMessage())) {
    factory = GsonConverterFactory.create(); // fall back to default Gson
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling GsonConverterFactory.create(null) directly, or passing a field/parameter that resolves to null (e.g. an uninitialized Gson field, a DI-provided Gson that was never bound, or a lateinit var read before assignment).

Common situations: A Dagger/Hilt @Provides method returning null because its dependency was missing, a Gson instance built conditionally and left null on a code path, or unit tests constructing the factory with a mock that returned null.

Related errors


AI-assisted analysis of lysine-dev/retrofit@d0b112dad0 (2026-08-13). Data as JSON: /api/errors/1f3f762128a6fc0f. Report an issue: GitHub.