HarperFast / HarperFast/harper
REST iterable responses swallow generator throws into an in-band {"error"} array element with HTTP 200
- Dominant language
- JavaScript
- Stars
- 89
- Forks
- 10
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 200
Description
## What happens
A REST iterable response (custom Resource returning an async iterator) whose generator **throws** mid-serialization delivers the error as an in-band `{"error": "..."}` **array element** with HTTP 200. A client doing `res.ok && await res.json()` silently treats the error as a data row: mid-stream the payload is `[{"n":0},{"n":1},{"error":…}]` — indistinguishable from a 3-row result without schema knowledge. For the pre-first-yield case nothing has been committed to the wire yet and a real 500 is freely available, so at minimum that case is indefensible.
## Mechanism (on `origin/main` @ e16d9616)
`server/serverHelpers/JSONStream.ts` (moved from `resources/JSONStream.ts`) — `serialize()`'s generator `catch (error)` turns any iterator throw, sync or async, pre- or post-first-yield, into `{ done: false, value: { error: errorToString(error) } }` and continues the array serialization; nothing changes the eventual HTTP status.
## Suggested fix shape
- Pre-first-byte: propagate the error → real 4xx/5xx.
- Post-first-byte (status already committed): terminate the stream *abnormally* rather than emitting a well-formed array close around an in-band error object — the SSE/NDJSON error contract pinned in `integrationTests/server/stream-error-contract.test.ts` (PR #2070) is the precedent; the JSON-array surface is the one that still lies.
## Existing work checked
#1650 is the `[Epic] HTTP error-hygiene` umbrella with no body detail — no dedicated issue describes this mechanism. #2329 (F-275) is a sibling on a different path (`transformIterable`/SSE/NDJSON `writeHead` timing at `server/http.ts:621`), not a dup. Searched harper + harper-pro, open+closed, for JSONStream / swallowed generator throw: nothing else on point.
## What this does not prove
GraphQL and MCP iterable surfaces were not exercised; only the REST JSON-array path is confirmed.
---
*From dispatch QA finding F-277, verified against harper origin/main e16d9616, 2026-08-29.*
Contributor guide
Research direction
Start with server/serverHelpers/JSONStream.ts, especially serialize() and its generator catch, then read integrationTests/server/stream-error-contract.test.ts and the REST iterable response path. Done means pre-first-byte iterator failures produce a real 4xx/5xx, while post-first-byte failures terminate abnormally without emitting an in-band error element or a normal array close.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, node.js
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100