Summary
On a self-hosted instance that uses Cloudflare R2 as the S3 bucket, camera-only Instant Mode recordings from Cap Desktop (Windows) never finish uploading. Screen, window and area Instant recordings upload and play fine against the same bucket.
cap-web logs this on each camera-only attempt:
Multipart upload failed: eS [StorageError]: { "cause": S3Error: { "cause": InvalidPart: All non-trailing parts must have the same length. } (cause: InvalidPart: All non-trailing parts must have the same length.) }
The video row is created with source: {"type": "desktopMP4"}, but no outputKey, previewKey or thumbnailKey is ever set.
Likely cause
Cloudflare R2's multipart API has a rule AWS S3 doesn't: every part except the last must be exactly the same size (R2 docs: "All parts except the last one must be the same size"). The progressive uploader appears to send variable-size parts: flushes of at least MIN_PART_SIZE_BYTES (5 MiB), sized by whatever was buffered, as in packages/recorder-core/src/instant-mp4-uploader.ts. AWS and MinIO accept that; R2 rejects it at CompleteMultipartUpload. Camera-only seems to take a different upload path from screen recordings, so only that mode hits it.
Environment
- Self-hosted via Docker Compose,
ghcr.io/capsoftware/cap-web@sha256:8ee4cbd3fd87... (latest as of 2026-09-07) and cap-media-server@sha256:886ecc9b5684...
- Storage: Cloudflare R2,
CAP_AWS_REGION=auto, path-style, private bucket
- Cap Desktop for Windows (current download as of 2026-09-11; bundled CLI 0.1.0)
Steps to reproduce
- Point Cap Desktop at a self-hosted server whose bucket is Cloudflare R2.
- Instant Mode, choose camera only (no screen), record about 30 s, stop.
- The upload never completes;
cap-web logs the InvalidPart error above.
- Repeat with a screen or window target: it works.
Possible fixes
- Use fixed-size parts for all non-final parts (re-chunk the buffer to a constant size, e.g. 5 or 8 MiB, carrying the remainder forward), or
- Detect R2 endpoints (or add a
S3_FIXED_PART_SIZE option) and switch to constant part sizes there.
Workaround for now: record camera-only videos in Studio Mode.
Summary
On a self-hosted instance that uses Cloudflare R2 as the S3 bucket, camera-only Instant Mode recordings from Cap Desktop (Windows) never finish uploading. Screen, window and area Instant recordings upload and play fine against the same bucket.
cap-weblogs this on each camera-only attempt:The video row is created with
source: {"type": "desktopMP4"}, but nooutputKey,previewKeyorthumbnailKeyis ever set.Likely cause
Cloudflare R2's multipart API has a rule AWS S3 doesn't: every part except the last must be exactly the same size (R2 docs: "All parts except the last one must be the same size"). The progressive uploader appears to send variable-size parts: flushes of at least
MIN_PART_SIZE_BYTES(5 MiB), sized by whatever was buffered, as inpackages/recorder-core/src/instant-mp4-uploader.ts. AWS and MinIO accept that; R2 rejects it atCompleteMultipartUpload. Camera-only seems to take a different upload path from screen recordings, so only that mode hits it.Environment
ghcr.io/capsoftware/cap-web@sha256:8ee4cbd3fd87...(latest as of 2026-09-07) andcap-media-server@sha256:886ecc9b5684...CAP_AWS_REGION=auto, path-style, private bucketSteps to reproduce
cap-weblogs theInvalidParterror above.Possible fixes
S3_FIXED_PART_SIZEoption) and switch to constant part sizes there.Workaround for now: record camera-only videos in Studio Mode.