didi/DoKit · error · IllegalArgumentException

source == null

Error message

source == null

What it means

ByteCountBufferedSinkV4 is the OkHttp 4 / okio Kotlin-era variant of DoraomonKit's chunked BufferedSink; writeAll(Source) throws IllegalArgumentException('source == null') when passed a null Source, mirroring okio's built-in argument validation. It exists because the okio API differs between OkHttp 3 and 4.

Source

Thrown at Android/dokit-okhttp-v4/src/main/java/com/didichuxing/doraemonkit/okhttp_api/ByteCountBufferedSinkV4.java:40

 * <p>
 * Created by jintai on 2020-10-20 16:07
 * 支持4.3.0+ 4.0.0 4.1.0 4.2.0 不支持
 */
public class ByteCountBufferedSinkV4 implements BufferedSink {

    private final long mByteCount;
    private final Sink mOriginalSink;
    private final BufferedSink mDelegate;

    public ByteCountBufferedSinkV4(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 before calling writeAll; skip for bodyless requests
  2. Substitute an empty Buffer for a null Source when a zero-byte write is semantically correct
  3. Guard at the interceptor level: if (request.body == null) skip capture entirely

Example fix

// before
byteCountSink.writeAll(responseBodySource); // null for 204/HEAD

// after
if (responseBodySource != null) {
  byteCountSink.writeAll(responseBodySource);
}
Defensive patterns

Strategy: validation

Validate before calling

if (source != null) { byteCountSink.writeAll(source); }

Prevention

When it happens

Trigger: Calling writeAll(source) with null — a nullable Source from an interceptor where the request/response body was absent (GET with no body, 204, HEAD) and code passed body?.source() result or a null-returning lookup straight through.

Common situations: DoraemonKit network interception on OkHttp 4 clients where body is null for bodyless requests. Java callers of the V4 wrapper forgetting null handling that Kotlin's own Buffer types would enforce via platform types.

Related errors


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