unslothai/unsloth · error · ValueError

{path}: not valid JSON: {exc}

Error message

{path}: not valid JSON: {exc}

What it means

Thrown by streamResearchEvents (research-api.ts:144-208) when the POST to /api/chat/research-runs/{id}/events returns response.ok === true but response.body is null/undefined. A 200 response to a text/event-stream request must always carry a body; a null body means the fetch stack (service worker, polyfill, HTTP/1.0 proxy, or a mocked fetch) did not expose streaming, so the SSE reader cannot be constructed.

Source

Thrown at scripts/check_new_install_scripts.py:123

            )
            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 None
    try:
        meta = json.loads(body)
    except json.JSONDecodeError:
        return None

View on GitHub (pinned to 203007d190)

Solutions

  1. Hard-reload with service workers disabled (DevTools > Application > Bypass for network) to rule out a synthesized Response.
  2. Test in a current Chrome/Firefox; if the error follows the browser, the fetch implementation lacks streaming support.
  3. Check whether a proxy between client and backend buffers SSE; configure it to stream (disable response buffering for text/event-stream).
  4. In tests, mock fetch with a Response whose body is a ReadableStream (e.g. new Response(sseChunks.join(''), {headers:{'content-type':'text/event-stream'}})).

Example fix

// before (test mock)
fetchMock.mockResolvedValue(new Response());

// after — give the mock a real streaming body
fetchMock.mockResolvedValue(new Response('id:1\nevent:status\ndata:{"run":{}}\n\n', { headers: { 'content-type': 'text/event-stream' } }));
Defensive patterns

Strategy: type-guard

Validate before calling

async function probeEventStreamSupport(): Promise<boolean> {
  const res = await fetch('/api/health', { method: 'POST' });
  return typeof res.body?.getReader === 'function';
}

Type guard

function hasStreamBody(response: Response): response is Response & { body: ReadableStream<Uint8Array> } {
  return response.body instanceof ReadableStream;
}

Try / catch

try {
  for await (const event of streamResearchEvents(id, after, signal)) { handle(event); }
} catch (error) {
  if (error instanceof Error && error.message === "Research event stream returned no response body") {
    // fetch stack cannot stream: disable live research updates or reload without service worker
  } else throw error;
}

Prevention

When it happens

Trigger: POST /api/chat/research-runs/{id}/events?after=N with accept: text/event-stream succeeding at the HTTP layer but yielding no stream — e.g. a service worker or older browser fetch polyfill returning a synthesized Response without a body, a proxy that buffers the whole stream and closes it oddly, or test mocks that return new Response() with no body argument.

Common situations: Running the studio frontend under an aggressive PWA/service-worker cache; older Safari or embedded webviews with incomplete streaming fetch; e2e tests mocking fetch without a ReadableStream; corporate proxies that strip transfer-encoding.

Related errors


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/21c63fe3521d5e3b. Report an issue: GitHub.