{"record":{"id":"5d686694c3987e34","repo":"didi/DoKit","slug":"source-null-5d6866","errorCode":null,"errorMessage":"source == null","messagePattern":"source == null","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"Android/dokit-okhttp-v4/src/main/java/com/didichuxing/doraemonkit/okhttp_api/ByteCountBufferedSinkV4.java","lineNumber":40,"sourceCode":" * <p>\n * Created by jintai on 2020-10-20 16:07\n * 支持4.3.0+ 4.0.0 4.1.0 4.2.0 不支持\n */\npublic class ByteCountBufferedSinkV4 implements BufferedSink {\n\n    private final long mByteCount;\n    private final Sink mOriginalSink;\n    private final BufferedSink mDelegate;\n\n    public ByteCountBufferedSinkV4(Sink sink, long byteCount) {\n        this.mOriginalSink = sink;\n        this.mDelegate = Okio.buffer(mOriginalSink);\n        this.mByteCount = byteCount;\n    }\n\n    @Override\n    public long writeAll(Source source) throws IOException {\n        if (source == null) throw new IllegalArgumentException(\"source == null\");\n        long totalBytesRead = 0;\n        for (long readCount; (readCount = source.read(buffer(), mByteCount)) != -1; ) {\n            totalBytesRead += readCount;\n            emitCompleteSegments();\n        }\n        return totalBytesRead;\n    }\n\n    @Override\n    public BufferedSink write(byte[] source, int offset, int byteCount) throws IOException {\n        if (!isOpen()) throw new IllegalStateException(\"closed\");\n        //计算出要写入的次数\n        long count = (long) Math.ceil((double) source.length / mByteCount);\n        for (int i = 0; i < count; i++) {\n            //让每次写入的字节数精确到mByteCount 分多次写入\n            long newOffset = i * mByteCount;\n            long writeByteCount = Math.min(mByteCount, source.length - newOffset);\n            buffer().write(source, (int) newOffset, (int) writeByteCount);","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/didi/DoKit/blob/626827cddb2feb2f3aee87a52a064b4e5ca2bed4/Android/dokit-okhttp-v4/src/main/java/com/didichuxing/doraemonkit/okhttp_api/ByteCountBufferedSinkV4.java#L22-L58","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Null-check the Source before calling writeAll; skip for bodyless requests","Substitute an empty Buffer for a null Source when a zero-byte write is semantically correct","Guard at the interceptor level: if (request.body == null) skip capture entirely"],"exampleFix":"// before\nbyteCountSink.writeAll(responseBodySource); // null for 204/HEAD\n\n// after\nif (responseBodySource != null) {\n  byteCountSink.writeAll(responseBodySource);\n}","handlingStrategy":"validation","validationCode":"if (source != null) { byteCountSink.writeAll(source); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Guard interceptor capture with request.body() != null before pulling sources","Substitute an empty Buffer when a null Source means 'empty body'"],"tags":["okio","okhttp4","doraemonkit","null-check","java"],"backgroundTag":null,"analyzedSha":"626827cddb2feb2f3aee87a52a064b4e5ca2bed4","analyzedAt":"2026-08-14T12:45:58.758Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}