Skip to content

fix(android): reject a concurrent startRecording() instead of crashing - #4225

Open
radko93 wants to merge 2 commits into
margelo:mainfrom
radko93:fix/android-reject-concurrent-recorder-start
Open

radko93 wants to merge 2 commits into
margelo:mainfrom
radko93:fix/android-reject-concurrent-recorder-start

Conversation

@radko93

@radko93 radko93 commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

Problem

On Android, starting a second Recorder of the same CameraVideoOutput while the first one is still recording crashes the app.

All Recorders of one output share a single CameraX Recorder. When it already has an active or pending recording, PendingRecording.start() throws IllegalStateException synchronously. HybridVideoRecorder.startRecording calls it inside executor.execute without a catch, so the exception escapes the executor and kills the process. The per-Recorder "Active recording already in progress!" guard does not help, because each Recorder has its own executor and state.

iOS already handles this: it checks videoOutput.isRecording and rejects the promise with "Active recording already in progress!".

We see this crash in production (a dozen per month in our app).

Reproduction

The first commit adds a harness test to visioncamera.video.harness.ts: start Recorder 1, then start Recorder 2 of the same output, expect the second start to reject and the first recording to finish normally.

On main (API 30 emulator, example app) the test kills the app:

FATAL EXCEPTION: com.margelo.nitro.recorder
java.lang.IllegalStateException: A recording is already in progress. Previous recordings must be stopped before a new recording can be started.
    at androidx.camera.video.Recorder.start(Recorder.java:1090)
    at androidx.camera.video.PendingRecording.start(PendingRecording.kt:234)
    at com.margelo.nitro.camera.hybrids.recording.HybridVideoRecorder.startRecording$lambda$1(HybridVideoRecorder.kt:56)
    ...

Run it with:

bun run test:harness:android -- --testPathPatterns=video -t "rejects starting a second Recorder"

Change

Catch IllegalStateException around pendingRecording.start(...) and reject the startRecording() promise, like iOS does. Errors still propagate. Most of the diff is re-indentation; hiding whitespace shows the actual change.

Verification

  • New test: crashes on main, passes with the fix (API 30 emulator).
  • Full visioncamera.video.harness.ts on an API 35 emulator: everything passes except the two "records at the device's maximum/minimum supported video resolution" tests, which fail the same way on main (the emulated camera always records 720p).
  • bun run lint-kotlin, biome and tsc are clean.
  • iOS not run; the test relies on the existing iOS guard.

Generated with Claude Code

radko93 and others added 2 commits October 19, 2026 19:14
Starting a second `Recorder` of the same `CameraVideoOutput` while the first
one is recording must reject. On Android this currently crashes the app with
`IllegalStateException: A recording is already in progress`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CameraX `PendingRecording.start()` throws `IllegalStateException` synchronously
when the output's `Recorder` already has an active or pending recording. That
happens when a second `Recorder` of the same `CameraVideoOutput` is started
while the first one is still recording. The throw escaped the recorder's
executor and crashed the app. Reject the `startRecording()` promise instead,
which matches iOS ("Active recording already in progress!").

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 19, 2026

Copy link
Copy Markdown

@radko93 is attempting to deploy a commit to the Margelo Team on Vercel.

A member of the Team first needs to authorize it.

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant