unslothai/unsloth · warning · TimeoutError
deadline reached while pacing before {method} {_redact_url(u
Error message
deadline reached while pacing before {method} {_redact_url(url)} What it means
Thrown (or surfaced via setModelsError/toast) by bailIfLoadInFlight in use-chat-model-runtime.ts:633-655 when a model load is requested while a different load (different id, GGUF variant, or native-path token) is already in flight. Same-pick duplicates are silently ignored; different picks set modelsError, throw when throwOnError was requested (the helper form of the selection), and toast. This centralizes the single-flight guard so every load entry point is covered.
Source
Thrown at scripts/virustotal_scan.py:402
full socket timeout, so a loop that only checks afterwards can overrun the
caller's budget by minutes and get the whole step killed before it writes
a summary.
"""
headers = {"x-apikey": self._api_key, "accept": "application/json"}
if extra_headers:
headers.update(extra_headers)
backoff = self._request_interval if self._request_interval > 0 else 1.0
last_error = ""
for attempt in range(1, max_attempts + 1):
if deadline is not None and self._clock() >= deadline:
raise TimeoutError(f"deadline reached before {method} {_redact_url(url)}")
self._throttle(deadline)
# Re-check: pacing sleeps between the check above and the call below, so
# without this a request could start after the deadline and then block
# for the full socket timeout, overrunning the step's own budget.
if deadline is not None and self._clock() >= deadline:
raise TimeoutError(
f"deadline reached while pacing before {method} {_redact_url(url)}"
)
try:
# Clamp the socket budget to what is left. Without this a call that
# starts just before the deadline can still block for the full
# socket timeout and consume the whole cushion the step relies on
# to write its summary.
socket_timeout = _SOCKET_TIMEOUT
if deadline is not None:
socket_timeout = max(1.0, min(socket_timeout, deadline - self._clock()))
status, payload = self._transport(method, url, headers, body, socket_timeout)
except Exception as error: # network layer, DNS, TLS, truncated read
last_error = f"{type(error).__name__}: {error}"
status, payload = 0, b""
finally:
self._last_request_at = self._clock()
if status == 429:View on GitHub (pinned to 203007d190)
Solutions
- Wait for the in-flight load to finish or cancel it (stop/cancel control) before requesting another.
- If the UI seems stuck 'loading' with no real load, reload the page or trigger a status refresh to clear the stale loadingModelRef/loadingModelPick state.
- Programmatic callers: pass throwOnError: true and catch this error to queue a retry once the current load completes.
Example fix
// before
void runtime.load(nextModel);
// after — honor the single-flight guard and queue
try {
await runtime.load({ ...nextModel, throwOnError: true });
} catch (e) {
if (e instanceof Error && e.message.startsWith("Another model is already loading")) {
await waitForCurrentLoad();
await runtime.load({ ...nextModel, throwOnError: true });
} else throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
function canStartLoad(state: { loadingModel: unknown; loadingModelPick: unknown }): boolean {
return !state.loadingModel && !state.loadingModelPick;
} Type guard
function isLoadInFlightError(e: unknown): e is Error {
return e instanceof Error && e.message.startsWith('Another model is already loading');
} Try / catch
try {
await loadModel({ ...selection, throwOnError: true });
} catch (error) {
if (isLoadInFlightError(error)) {
await waitForLoadSettled(); // poll status or subscribe to the store
await loadModel({ ...selection, throwOnError: true });
} else throw error;
} Prevention
- Disable other model entries in the picker while a load is in flight (reflect loadingModelPick in the UI).
- Pass throwOnError: true in programmatic flows and handle it; the plain-string form only toasts.
- Clear stale loadingModelRef/loadingModelPick on status refresh so a dead load cannot block new ones.
When it happens
Trigger: Calling load with selection A while loadingModelRef.current or loadingModelPick holds a different pick B — e.g. double-clicking two different model rows, switching model mid-load from the sidebar, or a GGUF variant change while another variant is still loading. The throw only happens for the object-form selection with throwOnError: true.
Common situations: Impatient users clicking several models in quick succession; automated scripts/staged configs firing loads while a previous load is slow (large GGUF); switching from a local model to another while the first is downloading.
Related errors
- deadline reached before {method} {_redact_url(url)}
- VirusTotal returned HTTP {status} for {_redact_url(url)}
- VirusTotal request failed after {max_attempts} attempt(s): {
- VirusTotal hash lookup returned a malformed body
- A diffusion load is already in progress.
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/04b413120f53c8e7.
Report an issue: GitHub.