spring-projects/spring-ai · error · AnthropicIoException
Could not read content length
Error message
Could not read content length
What it means
When converting an okio BufferedSource into an OkHttp RequestBody (toHttpRequestBody), the client calls source.contentLength(), which can throw IOException for sources whose length is not directly readable. That IOException is wrapped in AnthropicIoException 'Could not read content length'.
Source
Thrown at models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/http/okhttp/SpringAiAnthropicHttpClient.java:399
private static String toBaseUrl(HttpUrl url) {
StringBuilder sb = new StringBuilder();
sb.append(url.scheme()).append("://").append(url.host());
if (url.port() != HttpUrl.defaultPort(url.scheme())) {
sb.append(':').append(url.port());
}
return sb.toString();
}
private static HttpRequestBody toHttpRequestBody(RequestBody source) {
final MediaType mediaType = source.contentType();
final String mediaTypeString = mediaType != null ? mediaType.toString() : null;
final long length;
try {
length = source.contentLength();
}
catch (IOException e) {
throw new AnthropicIoException("Could not read content length", e);
}
final boolean isOneShot = source.isOneShot();
return new HttpRequestBody() {
@Override
public @Nullable String contentType() {
return mediaTypeString;
}
@Override
public long contentLength() {
return length;
}
@Override
public boolean repeatable() {
return !isOneShot;
}View on GitHub (pinned to 98a7beda4f)
Solutions
- Supply request content from a replayable source: byte[] , File, or a string rather than a live stream.
- If streaming is required, implement/choose a body that sets a known Content-Length or uses chunked encoding.
- Verify the backing file/stream is open and readable before building the request.
- Catch AnthropicIoException and inspect the cause to identify which source failed.
Example fix
// before requestBuilder.content(new InputStreamContent(sourceStream)); // contentLength() throws // after byte[] bytes = sourceStream.readAllBytes(); requestBuilder.content(new ByteArrayContent(bytes));
Defensive patterns
Strategy: validation
Validate before calling
static byte[] toBytes(InputStream in) throws IOException {
return in.readAllBytes(); // materialize before building the request
} Type guard
static long safeContentLength(Source src) {
try { return src.contentLength(); }
catch (IOException e) { throw new IllegalStateException("Source cannot report length; buffer it first", e); }
} Try / catch
try {
return client.sendRequest(request);
} catch (AnthropicIoException e) {
if ("Could not read content length".equals(e.getMessage())) {
// rebuild request with buffered byte[] content
}
throw e;
} Prevention
- Prefer byte[]/File/String request content over live streams.
- Never reuse an already-consumed Source for a request body.
- Confirm backing files exist and are readable before building requests.
When it happens
Trigger: Sending a request whose body is backed by a stream/source that cannot report its length (e.g. a non-replayable streaming source, a file being concurrently modified, or a source already consumed) while building the outgoing HTTP request.
Common situations: Uploading a file that was deleted or truncated mid-request; passing a streaming Source (e.g. from a socket or pipe) as request content; double-consuming a request body source.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Failed to write request body
- Request failed
- Request failed
- Could not read content length
- Invalid filename for file '': must be a single path segment
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/7e2e9e0a654c0d61.
Report an issue: GitHub.