square/retrofit · error · NullPointerException

error == null

Error message

error == null

What it means

`Result<T>` is a value object representing the outcome of one HTTP call -- it holds either a Response or an error, never both, never neither. The factory method `Result.error(Throwable)` at Result.java:26 rejects a null throwable to preserve that invariant: an error Result must carry a real cause so downstream code (and `.error()`) can rely on it.

Source

Thrown at retrofit-adapters/rxjava/src/main/java/retrofit2/adapter/rxjava/Result.java:26

 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package retrofit2.adapter.rxjava;

import java.io.IOException;
import javax.annotation.Nullable;
import retrofit2.Response;

/** The result of executing an HTTP request. */
public final class Result<T> {
  @SuppressWarnings("ConstantConditions") // Guarding public API nullability.
  public static <T> Result<T> error(Throwable error) {
    if (error == null) throw new NullPointerException("error == null");
    return new Result<>(null, error);
  }

  @SuppressWarnings("ConstantConditions") // Guarding public API nullability.
  public static <T> Result<T> response(Response<T> response) {
    if (response == null) throw new NullPointerException("response == null");
    return new Result<>(response, null);
  }

  private final @Nullable Response<T> response;
  private final @Nullable Throwable error;

  private Result(@Nullable Response<T> response, @Nullable Throwable error) {
    this.response = response;
    this.error = error;
  }

  /**

View on GitHub (pinned to d0b112dad0)

Solutions

  1. Pass a non-null Throwable, e.g. `Result.error(new IOException("boom"))`.
  2. If the source can legitimately be null, supply a sentinel/default exception: `Result.error(t != null ? t : new IllegalStateException("unknown"))`.
  3. Prefer letting the built-in RxJavaCallAdapter construct Result instances rather than building them yourself.

Example fix

// before
Result<User> r = Result.error(getErrorOrNull()); // NPE if null

// after
Throwable t = getErrorOrNull();
Result<User> r = Result.error(t != null ? t : new IllegalStateException("no cause"));
Defensive patterns

Strategy: validation

Validate before calling

// Validate before constructing:
static <T> Result<T> safeError(Throwable t) {
    if (t == null) throw new IllegalArgumentException("error must not be null");
    return Result.error(t);
}

Try / catch

// If the throwable may be null, guard at the call site:
try {
    Result<User> r = Result.error(maybeNullThrowable);
} catch (NullPointerException e) {
    if (e.getMessage().equals("error == null")) {
        // supply a default cause or log and skip
        Result<User> r = Result.error(new IllegalStateException("unknown error"));
    } else throw e;
}

Prevention

When it happens

Trigger: Calling `Result.error(null)` directly in application code, a custom call adapter, a converter, or a test fixture. The null check fires immediately at Result.java:26.

Common situations: Writing a custom adapter that wraps failures and passing a null cause when a sub-call returned null; building Result instances by hand in tests; or chaining `Result.error(something_that_might_be_null)` without guarding.

Related errors


AI-assisted analysis of square/retrofit@d0b112dad0 (2026-08-04). Data as JSON: /data/errors/07f7ab75e3045039.json. Report an issue: GitHub.