{"record":{"id":"67c02dad3cd6db1c","repo":"Tencent/WeKnora","slug":"read-body-w","errorCode":null,"errorMessage":"read body: %w","messagePattern":"read body: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/infrastructure/docparser/image_resolver.go","lineNumber":1041,"sourceCode":"\t}\n\n\t// Determine MIME type from Content-Type header.\n\tct := resp.Header.Get(\"Content-Type\")\n\tmimeType, _, _ = mime.ParseMediaType(ct)\n\tif mimeType == \"\" {\n\t\tmimeType = \"application/octet-stream\"\n\t}\n\n\t// Only allow image content types (or octet-stream which we sniff later).\n\tif !strings.HasPrefix(mimeType, \"image/\") && mimeType != \"application/octet-stream\" {\n\t\treturn nil, \"\", fmt.Errorf(\"non-image content type: %s\", mimeType)\n\t}\n\n\t// Read body with size limit.\n\tlimited := io.LimitReader(resp.Body, maxRemoteImageSize+1)\n\tbody, err := io.ReadAll(limited)\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"read body: %w\", err)\n\t}\n\tif len(body) > maxRemoteImageSize {\n\t\treturn nil, \"\", fmt.Errorf(\"image exceeds %d bytes limit\", maxRemoteImageSize)\n\t}\n\n\t// If MIME was octet-stream, sniff the real type from body.\n\tif mimeType == \"application/octet-stream\" {\n\t\tdetected := http.DetectContentType(body)\n\t\tif strings.HasPrefix(detected, \"image/\") {\n\t\t\tmimeType = detected\n\t\t} else {\n\t\t\treturn nil, \"\", fmt.Errorf(\"downloaded data is not an image (sniffed: %s)\", detected)\n\t\t}\n\t}\n\n\treturn body, mimeType, nil\n}\n","sourceCodeStart":1023,"sourceCodeEnd":1059,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/infrastructure/docparser/image_resolver.go#L1023-L1059","documentation":"This error wraps an I/O failure while reading the remote image response body through an io.LimitReader capped at maxRemoteImageSize+1 bytes. It signals the body stream broke mid-read (connection reset, unexpected EOF, timeout) rather than a size violation.","triggerScenarios":"io.ReadAll on the limited body fails: connection reset by peer, unexpected EOF, TLS truncation, or context deadline exceeded while streaming a large image.","commonSituations":"Flaky image hosts dropping connections on large files, proxies terminating long downloads, context timeout too short for big images, network interruptions mid-transfer.","solutions":["Unwrap the error — connection reset/unexpected EOF usually means retry with backoff","Increase the download timeout/context budget for large images","Check proxy/LB idle-timeout settings that may cut long transfers","Skip persistently failing image URLs rather than blocking document processing"],"exampleFix":"// before\nlimited := io.LimitReader(resp.Body, maxRemoteImageSize+1)\nbody, err := io.ReadAll(limited)\nif err != nil { return nil, \"\", fmt.Errorf(\"read body: %w\", err) }\n// after\nlimited := io.LimitReader(resp.Body, maxRemoteImageSize+1)\nbody, err := io.ReadAll(limited)\nif err != nil {\n    if errors.Is(err, context.DeadlineExceeded) {\n        return nil, \"\", fmt.Errorf(\"read body (deadline exceeded): %w\", err)\n    }\n    return nil, \"\", fmt.Errorf(\"read body: %w\", err)\n}","handlingStrategy":"retry","validationCode":"// ensure enough time budget for large images before fetching\nif deadline, ok := ctx.Deadline(); ok && time.Until(deadline) < 10*time.Second {\n    var cancel context.CancelFunc\n    ctx, cancel = context.WithTimeout(context.Background(), 30*time.Second)\n    defer cancel()\n}","typeGuard":null,"tryCatchPattern":"data, mimeType, err := downloadImage(ctx, client, remoteURL)\nif err != nil {\n    var ne net.Error\n    if errors.As(err, &ne) && (ne.Timeout() || strings.Contains(err.Error(), \"unexpected EOF\")) {\n        // transient truncation: retry once with backoff\n        time.Sleep(time.Second)\n        return downloadImage(ctx, client, remoteURL)\n    }\n    return nil, \"\", fmt.Errorf(\"read body: %w\", err)\n}","preventionTips":["Set generous context timeouts for large image downloads","Retry on transient read errors (EOF, connection reset) with backoff","Check proxy/LB idle timeouts against expected image sizes","Cap image size on the client side so downloads finish quickly"],"tags":["io","http","network","image","truncation"],"backgroundTag":"connection-reset-by-peer","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}