PutObjectStream omitted Content-Length because client-reported sizes are untrusted, but Cloudflare R2 rejects unsized PutObject bodies with 411 MissingContentLength. Route streaming uploads through the SDK's multipart manager, which buffers fixed-size parts (8 MiB, sequential) and sends each with a known length, preserving bounded memory for untrusted stream sizes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012e3QjbPo96ed9Mn2qRiUkh