alyssaxuu/screenity · error · Error
Camera track has ended
Error message
Camera track has ended
What it means
After setting up the camera uploader, CloudRecorder grabs the first video track from the stored camera MediaStream and throws if its readyState is already 'ended'. A video track ends when its source device is disconnected, revoked, or stopped, so recording cannot proceed. This guard prevents starting an encoder against a dead track.
Source
Thrown at src/pages/CloudRecorder/CloudRecorder.jsx:4234
camera: offset,
ts: now,
};
patchTrackState("camera", {
lastUploadOffset: offset,
uploaderUpdatedAt: now,
});
if (now - (lastUploadProgress.current.lastPersistAt || 0) > 2000) {
lastUploadProgress.current.lastPersistAt = now;
persistSessionState();
}
},
onStall: onStall("camera"),
onTelemetry: onUploaderTelemetry("camera"),
onStateChange: onUploaderStateChange("camera"),
});
const track = cameraStream.current.getVideoTracks()[0];
if (track?.readyState === "ended") {
throw new Error("Camera track has ended");
}
let { width, height } = track.getSettings();
if (encoderKinds.camera === "webcodecs") {
const downscaled = computeEncodedDimensions({ width, height });
if (downscaled.width > 0 && downscaled.height > 0) {
width = downscaled.width;
height = downscaled.height;
}
}
// Omit linkedMediaId; server groups partners by shared sceneId
// in usedIn now. Lifts the serial wait on screen's mediaId
// (~3s dev, 500ms-1s prod).
cameraInitOpts = {
title: "Camera Recording",
type: "camera",
linkedMediaId: null,
width,
height,View on GitHub (pinned to 512606387b)
Solutions
- Retry getUserMedia to obtain a fresh camera stream, then rebuild the uploader with the new track.
- Listen for track 'ended' events on cameraStream.current and prompt the user to reconnect/select a camera before starting the recording.
- Check navigator.mediaDevices.enumerateDevices() for an available videoinput and guide the user to reselect it in device settings.
- Stop and clean up the current recorder session (cancel encoders/uploads) so a stale stream is not reused on retry.
- Avoid calling track.stop() on the camera stream anywhere before recording starts; audit shared references to the stream.
Example fix
// before
const track = cameraStream.current.getVideoTracks()[0];
if (track?.readyState === "ended") {
throw new Error("Camera track has ended");
}
// after
let track = cameraStream.current.getVideoTracks()[0];
if (!track || track.readyState === "ended") {
cameraStream.current = await navigator.mediaDevices.getUserMedia({ video: true });
track = cameraStream.current.getVideoTracks()[0];
} Defensive patterns
Strategy: type-guard
Validate before calling
const track = cameraStream.current?.getVideoTracks()[0];
if (!track || track.readyState !== "live") {
cameraStream.current = await navigator.mediaDevices.getUserMedia({ video: true });
} Type guard
function hasLiveCameraTrack(stream) {
const track = stream?.getVideoTracks()[0];
return !!track && track.readyState === "live";
} Try / catch
try {
startCameraUploader();
} catch (err) {
if (err.message === "Camera track has ended") {
await reacquireCameraStream();
startCameraUploader();
} else {
throw err;
}
} Prevention
- Subscribe to track 'ended' events and prompt reconnection immediately
- Enumerate videoinput devices before starting and verify camera availability
- Never call track.stop() on the camera stream before recording starts
- Re-acquire the stream after devicechange events
When it happens
Trigger: The webcam is unplugged or the USB hub drops between getUserMedia and uploader start; the user revokes camera permission via the browser's site controls; another application or code path calls track.stop() on the camera stream before this point.
Common situations: Laptop dock/undock during recording setup; user switches cameras in OS settings mid-flow; camera used exclusively by another app (Zoom/Teams) causing device release; long stalls before start where the OS turned the camera off.
Related errors
- Missing projectId
- Missing sceneId in uploadMeta
- No valid media uploaded - both screen and camera mediaId are
- Invalid reuse object: must have both videoId and mediaId
AI-assisted analysis of alyssaxuu/screenity@512606387b (2026-09-02).
Data as JSON: /api/errors/4fb913ead503f560.
Report an issue: GitHub.