Skip to content

Self-hosted + Cloudflare R2: camera-only Instant recordings fail with "InvalidPart: All non-trailing parts must have the same length" #2275

Description

@evanshields

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

  1. Point Cap Desktop at a self-hosted server whose bucket is Cloudflare R2.
  2. Instant Mode, choose camera only (no screen), record about 30 s, stop.
  3. The upload never completes; cap-web logs the InvalidPart error above.
  4. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions