unslothai/unsloth · error · FileNotFoundError
lockfile not found: {path}
Error message
lockfile not found: {path} What it means
ResearchApiError thrown by the shared json() helper in research-api.ts:49-65 when a /api/chat/research-runs request fails and the error body contains neither a string `detail` nor a string `message`. Unlike a plain Error, it carries the HTTP status on error.status so callers (e.g. isPermanentResearchError at research-api.ts:216) can distinguish retryable 5xx from permanent 4xx.
Source
Thrown at scripts/check_new_install_scripts.py:119
scripts = entry.get("scripts") or {}
lifecycle = any(
isinstance(scripts, dict) and scripts.get(hook)
for hook in ("preinstall", "install", "postinstall")
)
if lifecycle:
ver = entry.get("version") or "<unversioned>"
seen[f"{name}@{ver}"] = name
_walk_v1(entry.get("dependencies"), depth = depth + 1)
if version == 1 or "dependencies" in lock:
_walk_v1(lock.get("dependencies") or {})
return seen
def _load_lockfile(path: Path) -> dict:
if not path.exists():
raise FileNotFoundError(f"lockfile not found: {path}")
try:
return json.loads(path.read_text(encoding = "utf-8"))
except json.JSONDecodeError as exc:
raise ValueError(f"{path}: not valid JSON: {exc}") from exc
# Registry lookup for the postinstall command body (best-effort).
def _fetch_registry_scripts(name: str, version: str) -> dict[str, str] | None:
"""Return {hook: command} for lifecycle hooks in registry metadata; None on any error (never raises)."""
safe_name = urllib.parse.quote(name, safe = "@/")
url = f"{REGISTRY_BASE}{safe_name}/{urllib.parse.quote(version)}"
try:
with urllib.request.urlopen(url, timeout = REGISTRY_TIMEOUT_SECS) as resp:
body = resp.read()
except (urllib.error.URLError, OSError, ValueError, TimeoutError):
return NoneView on GitHub (pinned to 203007d190)
Solutions
- Inspect error.status in a catch: if >= 500 treat as transient and retry via the existing reconnect logic; if 4xx fix the request payload.
- Reproduce the failing request in the Network tab and read the raw response body to find the server-side cause.
- If auth-related (401), re-login and retry.
- As a developer, stringify non-string detail values (FastAPI validation arrays) before falling back to the generic message.
Example fix
// before
const detail = (body as { detail?: unknown })?.detail;
// after — stringify FastAPI structured validation details
const detail = body?.detail;
const detailText = typeof detail === "string" ? detail : detail ? JSON.stringify(detail) : undefined; Defensive patterns
Strategy: retry
Type guard
function isResearchApiError(e: unknown): e is ResearchApiError {
return e instanceof Error && e.name === "ResearchApiError" && typeof (e as ResearchApiError).status === "number";
} Try / catch
try {
await createResearchRun(input);
} catch (error) {
if (isResearchApiError(error)) {
if (error.status >= 500) { /* transient: backoff and retry */ }
else { /* permanent 4xx: fix payload, do not retry */ }
} else throw error;
} Prevention
- Validate request payloads against the CreateResearchRunInput shape before posting to avoid 422s.
- Use error.status (set on ResearchApiError) rather than parsing the message string.
- Mirror the file's own isPermanentResearchError pattern for any new call sites.
When it happens
Trigger: POST /api/chat/research-runs, or any mutate() call, or the streamResearchEvents !response.ok path returning an error whose body is empty, null (json parse failed), or has non-string detail — e.g. a 500 with an empty body, a 422 with a structured (array/object) validation detail, or a proxied HTML error page.
Common situations: Backend research worker crashed mid-run (500 with no detail); misconfigured reverse proxy returning 502 HTML; FastAPI validation errors where detail is a list of objects rather than a string; expired auth yielding a non-JSON 401.
Related errors
- family {getattr(fam, 'name', fam)!r} declares no prequant_fi
- load timed out (last progress: {prog})
- {path}: not valid JSON: {exc}
- deadline reached before {method} {_redact_url(url)}
- Request failed (${status})
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/181e409f7217f233.
Report an issue: GitHub.