screenpipe/screenpipe · error
Monitor {} not found
Error message
Monitor {} not found What it means
start_monitor with only a monitor id performs a get_monitor_by_id lookup; when no monitor with that id is currently enumerated it fails with 'Monitor {id} not found'. This is the id-only path used by resume APIs and external control surfaces, and it fails whenever the referenced display is gone or its id changed.
Source
Thrown at crates/screenpipe-engine/src/vision_manager/manager.rs:534
}
/// Start recording on a specific monitor
pub async fn start_monitor(&self, monitor_id: u32) -> Result<()> {
// Preserve the cheap intent/idempotency guards before any OS lookup.
if self.user_disabled.contains(&monitor_id) {
debug!("Monitor {} is user-paused; skipping start", monitor_id);
return Ok(());
}
if self.recording_tasks.contains_key(&monitor_id) {
debug!("Monitor {} is already recording", monitor_id);
return Ok(());
}
// Public id-only callers (resume APIs and external control surfaces)
// still need a lookup. On macOS this path is bounded by the shared SCK
// enumeration admission budget in screenpipe-screen.
let monitor = get_monitor_by_id(monitor_id)
.await
.ok_or_else(|| anyhow::anyhow!("Monitor {} not found", monitor_id))?;
self.start_monitor_handle(monitor).await
}
/// Start from a monitor handle that was already returned by a bounded
/// enumeration. Startup, watchdog recovery, and hot-plug reconciliation
/// all have this handle in hand; re-enumerating by id here used to create
/// an unbounded second `SCShareableContent` callback during recovery.
pub(crate) async fn start_monitor_handle(
&self,
monitor: screenpipe_screen::monitor::SafeMonitor,
) -> Result<()> {
let monitor_id = monitor.id();
// Record selection intent before the user-pause guard. A paused display
// remains expected even though it intentionally has no active task.
self.expected_monitors
.write()
.unwrap_or_else(|e| e.into_inner())
.insert(monitor_id);View on GitHub (pinned to 4ebf712990)
Solutions
- Re-enumerate monitors via get_monitor_by_id/available list and use a fresh handle before starting
- Fall back to starting the primary or first available monitor when the saved id is missing
- Clear the stale monitor id from persisted settings when this error occurs
- Subscribe to hot-plug/display-change events to keep stored ids current
Example fix
// before
manager.start_monitor(saved_monitor_id).await?; // fails if id gone
// after
match manager.start_monitor(saved_monitor_id).await {
Ok(_) => (),
Err(e) if e.to_string().contains("not found") => {
if let Some(m) = first_available_monitor().await {
manager.start_monitor_handle(m).await?;
}
}
Err(e) => return Err(e.into()),
} Defensive patterns
Strategy: validation
Validate before calling
// Confirm the monitor exists before resuming by id
if get_monitor_by_id(monitor_id).await.is_none() {
// re-enumerate or fall back to first available monitor
return start_first_available_monitor().await;
}
manager.start_monitor(monitor_id).await?; Try / catch
match manager.start_monitor(monitor_id).await {
Err(e) if e.to_string().contains("not found") => {
warn!("monitor {monitor_id} gone; selecting current monitor");
let m = first_available_monitor().await.ok_or(anyhow!("no monitors"))?;
manager.start_monitor_handle(m).await
}
r => r,
} Prevention
- Prefer start_monitor_handle with a freshly enumerated handle over long-lived ids
- Invalidate stored monitor ids on hot-plug, sleep/wake, and reboot events
- Always offer a fallback to the primary/first monitor in resume flows
- Never persist monitor ids across machines or config restores
When it happens
Trigger: resume_monitor (or any external control API) called with a monitor_id that is no longer present — monitor unplugged, id re-assigned after replug/sleep, or the id came from a stale persisted config or another machine.
Common situations: Resuming a paused monitor after the user changed display setup; automations holding old ids across reboots; UI showing cached monitor list.
Related errors
- no displays enumerated (0 enumerated, 0 started)
- no monitors matched the allowed list (monitorIds may be stal
- Monitor not found
- Invalid monitor dimensions
- Monitor {} not found during refresh
AI-assisted analysis of screenpipe/screenpipe@4ebf712990 (2026-09-01).
Data as JSON: /api/errors/74938f0b5841a5a1.
Report an issue: GitHub.