@@ -1747,6 +1747,22 @@ def _is_transient_supervisor_error(exc: BaseException) -> bool:
17471747 return exc .code == "unknown_error" and exc .supervisor_message == ""
17481748
17491749
1750+ def _is_transient_supervisor_readiness_error (exc : BaseException ) -> bool :
1751+ """Return whether readiness polling can retry a Supervisor failure.
1752+
1753+ Mutation responses stay strict because their outcome can be ambiguous. A
1754+ read during a known restart window may also observe Supervisor's setup
1755+ state before the API becomes ready again.
1756+ """
1757+ return _is_transient_supervisor_error (exc ) or (
1758+ isinstance (exc , WSCommandError )
1759+ and exc .code == "unknown_error"
1760+ and (exc .supervisor_message or "" ).startswith (
1761+ "System is not ready with state: "
1762+ )
1763+ )
1764+
1765+
17501766def _supervisor_info_ready (
17511767 info : dict [str , Any ],
17521768 * ,
@@ -1811,7 +1827,7 @@ def _wait_supervisor_ready(
18111827 try :
18121828 info = ws .supervisor_api ("/supervisor/info" , method = "get" , timeout = 30.0 )
18131829 except _SUPERVISOR_WAIT_TRANSIENT_ERRORS as e :
1814- if not _is_transient_supervisor_error (e ):
1830+ if not _is_transient_supervisor_readiness_error (e ):
18151831 raise
18161832 # A Supervisor self-update can return a transient command error or
18171833 # drop the WebSocket. Preserve the failure for timeout diagnostics,
@@ -1821,7 +1837,7 @@ def _wait_supervisor_ready(
18211837 try :
18221838 ws .reconnect ()
18231839 except _SUPERVISOR_WAIT_TRANSIENT_ERRORS as reconnect_err :
1824- if not _is_transient_supervisor_error (reconnect_err ):
1840+ if not _is_transient_supervisor_readiness_error (reconnect_err ):
18251841 raise
18261842 # Handler-start timeouts and transport failures are expected
18271843 # while Supervisor/Core restarts; keep them visible in CI logs.
@@ -1863,7 +1879,7 @@ def _wait_core_version(
18631879 ws .reconnect ()
18641880 last_info = ws .supervisor_api ("/core/info" , method = "get" , timeout = 30.0 )
18651881 except _SUPERVISOR_WAIT_TRANSIENT_ERRORS as exc :
1866- if not _is_transient_supervisor_error (exc ):
1882+ if not _is_transient_supervisor_readiness_error (exc ):
18671883 raise
18681884 last_error = exc
18691885 LOG .debug ("Core still restarting after update: %r" , exc )
@@ -1894,7 +1910,7 @@ def _reconnect_during_supervisor_update(
18941910 try :
18951911 ws .reconnect ()
18961912 except _SUPERVISOR_WAIT_TRANSIENT_ERRORS as exc :
1897- if not _is_transient_supervisor_error (exc ):
1913+ if not _is_transient_supervisor_readiness_error (exc ):
18981914 raise
18991915 LOG .warning ("Reconnect %s failed: %r" , context , exc )
19001916 return exc
@@ -1917,7 +1933,7 @@ def _wait_supervisor_channel_metadata(
19171933 "/supervisor/info" , method = "get" , timeout = 30.0
19181934 )
19191935 except _SUPERVISOR_WAIT_TRANSIENT_ERRORS as exc :
1920- if not _is_transient_supervisor_error (exc ):
1936+ if not _is_transient_supervisor_readiness_error (exc ):
19211937 raise
19221938 last_error = exc
19231939 LOG .debug ("Transient Supervisor reload failure: %r" , exc )
@@ -1985,7 +2001,7 @@ def _apply_supervisor_image_update(
19852001 except _SupervisorReadinessTimeout :
19862002 raise
19872003 except _SUPERVISOR_WAIT_TRANSIENT_ERRORS as exc :
1988- if not _is_transient_supervisor_error (exc ):
2004+ if not _is_transient_supervisor_readiness_error (exc ):
19892005 raise
19902006 if time .monotonic () >= deadline :
19912007 raise TimeoutError (
0 commit comments