Mobile's own video transcode produces MP4s the relay rejects (422 media contains metadata)

Open Beginner friendly
#5,415 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
82/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Quiet
Tech stack
android, dart, flutter
Domain
mobile-dev

Research direction

Start in mobile/lib/shared/relay/media_upload.dart at uploadVideo and _transcodeVideoToMp4, then compare the generated MP4 with the metadata-free command in the issue. Confirm the output satisfies crates/buzz-media/src/validation.rs::validate_mp4_metadata_free and that a video produced by the Android pipeline is accepted by the relay.

Written by the indexing model from the issue text.

Description

Self-hoster report, reproduced against a live relay. Sending a video from the Android app fails well under any size limit:

upload failed (422): {"error":"media contains metadata or a non-canonical metadata channel"}

Reproduction (relay side, minimal)

# ffmpeg default output — carries metadata
ffmpeg -f lavfi -i testsrc=duration=2:size=320x240:rate=15 -pix_fmt yuv420p -movflags +faststart vid-normal.mp4
buzz upload file --file vid-normal.mp4
# -> relay error 422: {"error":"media contains metadata or a non-canonical metadata channel"}

# same content, metadata stripped
ffmpeg -i vid-normal.mp4 -map_metadata -1 -fflags +bitexact -movflags +faststart -c copy vid-stripped.mp4
buzz upload file --file vid-stripped.mp4
# -> 200, stored and served

So the relay policy works as designed: crates/buzz-media/src/validation.rs::validate_mp4_metadata_free walks the atom tree and rejects meta / non-canonical udta content. No complaint about the policy itself — stripping metadata from user media is a good default.

The bug

mobile/lib/shared/relay/media_upload.dart::uploadVideo transcodes the picked video with _transcodeVideoToMp4 and then uploads the result — but that output still carries metadata, so the app's own pipeline produces files its own relay refuses. From the user's side, sending a phone video simply fails with an error that reads like corruption.

Images do not have this problem because they go through sanitizeImageForUpload / sanitizeAnimatedImageForUpload. Video has no equivalent sanitisation step, and it looks like the generic file path may be exposed the same way.

Suggested fix

Add metadata stripping to the transcode invocation — the equivalent of -map_metadata -1 (plus bitexact) — so the transcoder emits exactly the canonical shape the validator accepts. That keeps the privacy property the relay is enforcing, and does it once, in the place that is already re-encoding the file anyway.

Two smaller things worth considering alongside it:

  • surface the relay's actual reason in the UI, since "contains metadata" is not actionable for a user who only picked a video from their gallery;
  • the same validator applies to plain file uploads, so a .mp4 attached as a file rather than a video would hit it too.

Related: #5414 (mobile hardcodes 100 MB caps and cannot read the relay's real limits). Different failure, same area — a self-hosted relay currently cannot receive video from the mobile app at any size.

Dominant language
Rust
Stars
33.7k
Forks
4.4k
Avg merge
1d 21h
Merged PRs (30d)
239

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from block/buzz

All issues in block/buzz

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.