didi/DoKit · error · IllegalArgumentException

source == null

Error message

source == null

What it means

ByteCountBufferedSinkV3 is DoraemonKit's okio BufferedSink wrapper that writes in fixed mByteCount chunks (used to intercept and mirror OkHttp request/response bodies). writeAll(Source) validates its argument up front, mirroring okio's own contract, and throws IllegalArgumentException on a null source before attempting any read.

Source

Thrown at Android/dokit-okhttp-v3/src/main/java/com/didichuxing/doraemonkit/okhttp_api/ByteCountBufferedSinkV3.java:35

/**
 * 可以设置每次写入大小的BufferedSink
 * <p>
 * Created by xiandanin on 2019-05-10 16:07
 */
public  class ByteCountBufferedSinkV3 implements BufferedSink {
    private final long mByteCount;
    private final Sink mOriginalSink;
    private final BufferedSink mDelegate;

    public ByteCountBufferedSinkV3(Sink sink, long byteCount) {
        this.mOriginalSink = sink;
        this.mDelegate = Okio.buffer(mOriginalSink);
        this.mByteCount = byteCount;
    }

    @Override
    public long writeAll(Source source) throws IOException {
        if (source == null) throw new IllegalArgumentException("source == null");
        long totalBytesRead = 0;
        for (long readCount; (readCount = source.read(buffer(), mByteCount)) != -1; ) {
            totalBytesRead += readCount;
            emitCompleteSegments();
        }
        return totalBytesRead;
    }

    @Override
    public BufferedSink write(byte[] source, int offset, int byteCount) throws IOException {
        if (!isOpen()) throw new IllegalStateException("closed");
        //计算出要写入的次数
        long count = (long) Math.ceil((double) source.length / mByteCount);
        for (int i = 0; i < count; i++) {
            //让每次写入的字节数精确到mByteCount 分多次写入
            long newOffset = i * mByteCount;
            long writeByteCount = Math.min(mByteCount, source.length - newOffset);
            buffer().write(source, (int) newOffset, (int) writeByteCount);

View on GitHub (pinned to 626827cddb)

Solutions

  1. Null-check the source and skip or substitute Buffer() (an empty Source) when null
  2. Fix the producer: map 'no body' to an empty okio Buffer instead of null
  3. In Kotlin, use 'source ?: Buffer()' or an explicit if-null guard

Example fix

// before
byteCountSink.writeAll(nullableSource);

// after
if (nullableSource != null) {
  byteCountSink.writeAll(nullableSource);
} else {
  byteCountSink.write(Buffer()); // or simply skip
}
Defensive patterns

Strategy: validation

Validate before calling

if (source != null) { byteCountSink.writeAll(source); } else { byteCountSink.write(new okio.Buffer()); }

Prevention

When it happens

Trigger: Calling writeAll(source) with null — typically when a response/request body Source resolved to null (empty body mapped to null, interceptor returning null for the body, or an upstream API returning null instead of an empty Source).

Common situations: OkHttp interceptors in DoraKit's network inspection flow where a HEAD/204 response has no body and the code passes body.source() from a null body. Third-party servers returning empty bodies handled as null. Kotlin code passing a nullable Source without a null check.

Related errors


AI-assisted analysis of didi/DoKit@626827cddb (2026-08-14). Data as JSON: /api/errors/4c80bf1201a78a72. Report an issue: GitHub.