{"record":{"id":"04b413120f53c8e7","repo":"unslothai/unsloth","slug":"deadline-reached-while-pacing-before-method-re","errorCode":null,"errorMessage":"deadline reached while pacing before {method} {_redact_url(url)}","messagePattern":"deadline reached while pacing before (.+?) (.+?)","errorType":"exception","errorClass":"TimeoutError","httpStatus":null,"severity":"warning","filePath":"scripts/virustotal_scan.py","lineNumber":402,"sourceCode":"        full socket timeout, so a loop that only checks afterwards can overrun the\n        caller's budget by minutes and get the whole step killed before it writes\n        a summary.\n        \"\"\"\n        headers = {\"x-apikey\": self._api_key, \"accept\": \"application/json\"}\n        if extra_headers:\n            headers.update(extra_headers)\n\n        backoff = self._request_interval if self._request_interval > 0 else 1.0\n        last_error = \"\"\n        for attempt in range(1, max_attempts + 1):\n            if deadline is not None and self._clock() >= deadline:\n                raise TimeoutError(f\"deadline reached before {method} {_redact_url(url)}\")\n            self._throttle(deadline)\n            # Re-check: pacing sleeps between the check above and the call below, so\n            # without this a request could start after the deadline and then block\n            # for the full socket timeout, overrunning the step's own budget.\n            if deadline is not None and self._clock() >= deadline:\n                raise TimeoutError(\n                    f\"deadline reached while pacing before {method} {_redact_url(url)}\"\n                )\n            try:\n                # Clamp the socket budget to what is left. Without this a call that\n                # starts just before the deadline can still block for the full\n                # socket timeout and consume the whole cushion the step relies on\n                # to write its summary.\n                socket_timeout = _SOCKET_TIMEOUT\n                if deadline is not None:\n                    socket_timeout = max(1.0, min(socket_timeout, deadline - self._clock()))\n                status, payload = self._transport(method, url, headers, body, socket_timeout)\n            except Exception as error:  # network layer, DNS, TLS, truncated read\n                last_error = f\"{type(error).__name__}: {error}\"\n                status, payload = 0, b\"\"\n            finally:\n                self._last_request_at = self._clock()\n\n            if status == 429:","sourceCodeStart":384,"sourceCodeEnd":420,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/scripts/virustotal_scan.py#L384-L420","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nvoid runtime.load(nextModel);\n\n// after — honor the single-flight guard and queue\ntry {\n  await runtime.load({ ...nextModel, throwOnError: true });\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith(\"Another model is already loading\")) {\n    await waitForCurrentLoad();\n    await runtime.load({ ...nextModel, throwOnError: true });\n  } else throw e;\n}","handlingStrategy":"try-catch","validationCode":"function canStartLoad(state: { loadingModel: unknown; loadingModelPick: unknown }): boolean {\n  return !state.loadingModel && !state.loadingModelPick;\n}","typeGuard":"function isLoadInFlightError(e: unknown): e is Error {\n  return e instanceof Error && e.message.startsWith('Another model is already loading');\n}","tryCatchPattern":"try {\n  await loadModel({ ...selection, throwOnError: true });\n} catch (error) {\n  if (isLoadInFlightError(error)) {\n    await waitForLoadSettled(); // poll status or subscribe to the store\n    await loadModel({ ...selection, throwOnError: true });\n  } else throw error;\n}","preventionTips":["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."],"tags":["concurrency","model-loading","state","frontend"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}