block / block/buzz

Mobile: iOS Voice Memo M4A is routed through video validation and rejected with 422

Open
#5,752 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
32.7k
Forks
4.3k
Avg merge
1d 13h
Merged PRs (30d)
253

Description

**Describe the bug**

Buzz Mobile cannot attach an Apple Voice Memo (`.m4a`). A real iOS upload
failed with HTTP 422:

```text
moov atom not at front of file (not fast-start)
```

After that failed attempt, retrying surfaced a follow-on error because the
temporary file-provider path no longer existed:

```text
PathNotFoundException: Cannot retrieve length of file, path = '.../Neue Aufnahme 3.m4a'
```

This is broader than a missing fast-start rewrite. Current `main`
(`a96af89526f7181543e7651100a944aa8e21812b`) routes every ISO-BMFF container
into the video pipeline:

```rust
fn should_stream_as_video(sniff: &[u8]) -> bool {
infer::get(sniff).is_some_and(|kind| kind.mime_type() == "video/mp4")
|| buzz_media::looks_like_iso_bmff(sniff)
}
```

An M4A Voice Memo is ISO-BMFF, so it reaches `validate_video_file()`. A normal
non-fast-start Voice Memo fails at `check_moov_before_mdat()` with the observed
422. Merely moving `moov` would not fully solve the case because the same video
validator later requires a video track.

The generic file path is not a fallback: `validate_file_content()` explicitly
rejects ISO-BMFF and every detected `audio/*` until an audio sanitizer exists.
The CLI similarly rejects a synthetic M4A before upload as
`unsupported file type: audio/m4a`.

Relevant code:

- `crates/buzz-relay/src/api/media.rs` (`should_stream_as_video`, `upload_blob`)
- `crates/buzz-media/src/validation.rs` (`validate_file_content`,
`validate_video_file`, `check_moov_before_mdat`)
- `mobile/lib/shared/relay/media_upload.dart` (`uploadFile` sends generic files
as `application/octet-stream`)

**Steps to reproduce**

1. Record a memo in Apple Voice Memos on iPhone.
2. Attach/share the resulting `.m4a` into a Buzz Mobile composer as a file.
3. Send the message.
4. Observe HTTP 422 with `moov atom not at front of file (not fast-start)`.
5. Retry after the failed attempt.
6. Observe that the temporary share/file-provider URL may already be gone,
producing `PathNotFoundException`.

A minimal local fixture showing the common layout can be generated with:

```bash
ffmpeg -f lavfi -i anullsrc=r=44100:cl=mono -t 1 \
-c:a aac -b:a 64k -movflags -faststart voice-memo-repro.m4a
```

Its top-level order is `ftyp | mdat | moov`. Buzz CLI currently rejects it as
`unsupported file type: audio/m4a`; the Mobile generic-file route reaches the
relay because it labels the body `application/octet-stream`.

**Expected behavior**

Preferred: Buzz accepts a normal AAC/M4A voice memo through an explicit audio
pipeline that remuxes/sanitizes the container, strips metadata, emits a stable
`audio/mp4`/`audio/m4a` descriptor, and does not require a video track.

Minimum safe behavior until audio uploads are supported:

- Detect M4A before enqueue/upload and show a clear "audio attachments are not
supported yet" message instead of a misleading video fast-start error.
- Copy file-provider/share-extension inputs into app-owned temporary storage
before queueing so a failed upload can be retried without
`PathNotFoundException`.

**Suggested regression coverage**

- Non-fast-start audio-only M4A (`ftyp | mdat | moov`) does not enter the video
validator.
- Fast-start audio-only M4A (`ftyp | moov | mdat`) does not fail for missing
video track when audio support is enabled.
- A queued iOS file-provider attachment remains readable for retry after the
provider revokes its temporary URL.

**Version and platform**

- Buzz version: unknown (reported 2026-08-13; bug is present in current source
at `a96af895`)
- OS: iOS / iPhone

**Logs / additional context**

No matching open or closed issue was found for `m4a`, `voice memo`,
`audio upload`, `moov atom`, or `fast-start` before filing.

Contributor guide

Open the contributing guide

Research direction

Start with should_stream_as_video and upload_blob in crates/buzz-relay/src/api/media.rs, then read validate_file_content, validate_video_file, and check_moov_before_mdat in crates/buzz-media/src/validation.rs. Compare these with uploadFile in mobile/lib/shared/relay/media_upload.dart and add the regression coverage described for audio-only M4A files and retryable file-provider attachments. Done means the selected supported or unsupported behavior is clear and the misleading 422 and retry path are covered.

Written by the indexing model from the issue text.

Assessment

Tech stack
dart, rust
Domain
backend, mobile
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.