refactor(errors): replace silent exception handling in console and server

This commit is contained in:
somew1nd committed 2026-09-01 17:57:15 -07:00
1 parent 41deb48005
commit c76c9bb7e8
20 files changed
+267 -107

No files matched your search

+14 -7
View File
@@ -121,7 +121,8 @@ async def mobile_inspect_trace(action: str, trace_id: str, step_number: int | No
try:
with open(plan_path, encoding="utf-8") as f:
plan_content = f.read()
except Exception:
except OSError:
# Unreadable plan file: the summary just omits the plan.
pass
try:
@@ -149,7 +150,8 @@ async def mobile_inspect_trace(action: str, trace_id: str, step_number: int | No
if step_dict.get(col):
try:
step_dict[col] = json.loads(step_dict[col])
except Exception:
except (ValueError, TypeError):
# Non-JSON column value: keep the raw string.
pass
cursor.execute(
@@ -163,7 +165,8 @@ async def mobile_inspect_trace(action: str, trace_id: str, step_number: int | No
if t_dict.get("payload"):
try:
t_dict["payload"] = json.loads(t_dict["payload"])
except Exception:
except (ValueError, TypeError):
# Non-JSON payload: keep the raw string.
pass
events.append(t_dict)
step_dict["interleaved_events"] = events
@@ -200,10 +203,12 @@ async def mobile_inspect_trace(action: str, trace_id: str, step_number: int | No
d_info = json.loads(row_dev["device_info"])
if isinstance(d_info, dict) and d_info.get("device_id"):
device_serial = d_info["device_id"]
except Exception:
except (ValueError, TypeError):
# Malformed device_info JSON: leave the serial unset.
pass
conn_dev.close()
except Exception:
except sqlite3.Error:
# The serial enriches the summary header only; skip it.
pass
device_info_str = f" | **Device Serial:** `{device_serial}`" if device_serial else ""
@@ -314,7 +319,8 @@ async def mobile_inspect_trace(action: str, trace_id: str, step_number: int | No
if step_dict.get(col):
try:
step_dict[col] = json.loads(step_dict[col])
except Exception:
except (ValueError, TypeError):
# Non-JSON column value: keep the raw string.
pass
cursor.execute(
@@ -335,7 +341,8 @@ async def mobile_inspect_trace(action: str, trace_id: str, step_number: int | No
if t_dict.get("payload"):
try:
t_dict["payload"] = json.loads(t_dict["payload"])
except Exception:
except (ValueError, TypeError):
# Non-JSON payload: keep the raw string.
pass
events.append(t_dict)
step_dict["interleaved_events"] = events
+37 -19
View File
@@ -64,14 +64,16 @@ def _session_tracked_by_lock(trace_id: str) -> bool:
for q_item in DeviceExecutionLock.get_queued_tasks():
if str(q_item.get("session_id")) == trace_id:
return True
except Exception:
pass
except Exception as exc:
# An unreadable queue may hide a live session; the caller then leans
# on DB/pid evidence, so surface the probe failure.
print(f"Could not read device queue for {trace_id}: {exc}", file=sys.stderr)
try:
for owner in DeviceExecutionLock.get_active_owners().values():
if owner.session_id and str(owner.session_id) == trace_id:
return True
except Exception:
pass
except Exception as exc:
print(f"Could not read device owners for {trace_id}: {exc}", file=sys.stderr)
return False
@@ -115,8 +117,9 @@ def _reconcile_task_state(
if row:
db_status = row["status"]
db_pid = row["pid"]
except Exception:
pass
except sqlite3.Error as exc:
# Reconciliation then relies on status.json and lock evidence only.
print(f"Could not read DB session row for {trace_id}: {exc}", file=sys.stderr)
if db_pid and db_pid != pid:
pid = db_pid
@@ -188,6 +191,8 @@ def _mark_liveness_failure(trace_id: str, status_data: dict[str, Any]) -> None:
payload={"trace_id": trace_id, "error": _LIVENESS_FAILURE_ERROR},
)
except Exception:
# Notification dispatch is best-effort; the failure verdict is
# already persisted in status.json.
pass
@@ -278,10 +283,13 @@ def mobile_manage_task(
device_serial = d_info["device_id"]
status_data["device_serial"] = device_serial
trace_store.write_status(trace_id, status_data)
except Exception:
except (ValueError, TypeError, OSError):
# Malformed device_info or failed cache write: the
# serial simply stays unknown for this poll.
pass
conn_dev.close()
except Exception:
except sqlite3.Error:
# DB probe for the serial is optional enrichment.
pass
if not device_serial and pid:
@@ -293,7 +301,8 @@ def mobile_manage_task(
status_data["device_serial"] = device_serial
trace_store.write_status(trace_id, status_data)
break
except Exception:
except OSError:
# Lock-owner probe / cache write failed: serial stays unknown.
pass
response: dict[str, Any] = {
@@ -329,7 +338,8 @@ def mobile_manage_task(
"task_status": run_outcome.get("task_status"),
**tests,
}
except Exception:
except (OSError, ValueError, TypeError):
# Unreadable or malformed run_outcome.json: omit the summary.
pass
break
@@ -394,7 +404,8 @@ def mobile_manage_task(
progress["latest_thought"] = p_obj["response"][0].get(
"text", ""
)
except Exception:
except (ValueError, TypeError, AttributeError):
# Unparseable thought payload: omit it.
pass
cur2.execute(
@@ -411,7 +422,9 @@ def mobile_manage_task(
act_payload = json.loads(row_action["payload"]).get(
"args", {}
)
except Exception:
except (ValueError, TypeError, AttributeError):
# Unparseable action payload: show the
# bare action name.
pass
progress["latest_action"] = (
f"{act_name}({act_payload})" if act_payload else act_name
@@ -433,7 +446,8 @@ def mobile_manage_task(
try:
with open(plan_path, encoding="utf-8") as f:
plan_content = f.read()
except Exception:
except OSError:
# Unreadable plan file: progress omits the plan.
pass
progress["task_plan"] = plan_content
else:
@@ -458,16 +472,18 @@ def mobile_manage_task(
try:
if is_daemon_running():
stopped_via_daemon = stop_task_on_daemon(trace_id)
except Exception:
pass
except Exception as exc:
# Fall through to direct process termination below.
print(f"Daemon stop attempt failed for {trace_id}: {exc}", file=sys.stderr)
# 2. Cancel queue reservation if present
queue_ticket = status_data.get("queue_ticket")
if queue_ticket:
try:
DeviceExecutionLock.cancel_reservation(queue_ticket)
except Exception:
pass
except OSError as exc:
# A stale reservation expires on its own; note the failure.
print(f"Could not cancel reservation {queue_ticket}: {exc}", file=sys.stderr)
# 3. If process PID is missing, try to resolve from active device owners
if not pid:
@@ -479,8 +495,10 @@ def mobile_manage_task(
status_data["pid"] = pid
trace_store.write_status(trace_id, status_data)
break
except Exception:
pass
except OSError as exc:
# Without a resolved pid the stop falls back to the
# daemon/queue outcome, so surface the probe failure.
print(f"Could not resolve owner pid for {trace_id}: {exc}", file=sys.stderr)
# 4. If process PID could not be determined and not stopped via daemon or queue
if not pid and not stopped_via_daemon and not queue_ticket:
+10 -3
View File
@@ -117,6 +117,8 @@ def _watch_spawn(
payload={"trace_id": trace_id, "error": error_text},
)
except Exception:
# Notification dispatch is best-effort; the failure verdict is
# already persisted in status.json.
pass
return False
@@ -321,8 +323,12 @@ def mobile_run_task(
"stdout_log": str(trace_store.get_trace_stdout_log_path(trace_id)),
"stderr_log": str(trace_store.get_trace_stderr_log_path(trace_id)),
}
except Exception:
pass
except Exception as exc:
# The queue probe is a rescue path for a slow daemon reply;
# its failure downgrades the verdict to "failed" below.
logging.getLogger("mcp_server").warning(
f"Could not verify daemon queue for '{trace_id}': {exc}"
)
# When Daemon is running, refuse to launch a conflicting standalone runner on the same device
logging.getLogger("mcp_server").warning(
@@ -392,7 +398,8 @@ def mobile_run_task(
ipc_port = read_ipc_port()
if ipc_port:
env["ARTEMIS_IPC_PORT"] = str(ipc_port)
except Exception:
except (OSError, ValueError):
# No readable IPC port file: the runner works without live telemetry.
pass
proc_kwargs = env_utils.get_detached_process_kwargs()