Found by adversarial audit @ 261d00b, survived refutation (conf 0.88).
Mechanism: caps permit topK=1000 × dim=16384 × batch=100 within the 32MiB body budget (query.ts:17-19). includeVectors decodes every hit to a full float array (query.ts:162-164) and Hono's c.json serializes monolithically via JSON.stringify→new Response(string) (hono context.js:375-381). Single ~66KB request ≈ 320MB string / ≥600MB peak; 100-query batch ≈ 13GB intermediates + multi-GB stringify target. Sync stringify blocks the event loop so the timeout middleware cannot preempt; hard OOM bypasses app.onError entirely. Same math applies to includeData once fat stored blobs exist (see companion cap finding fixed separately).
Fix direction: projected-size budget check before executing (topK×dim×bytes-per-float×batch vs configurable ceiling), and/or clamp effective topK when includeVectors=true, and/or stream-encode responses.
Found by adversarial audit @ 261d00b, survived refutation (conf 0.88).
Mechanism: caps permit topK=1000 × dim=16384 × batch=100 within the 32MiB body budget (query.ts:17-19). includeVectors decodes every hit to a full float array (query.ts:162-164) and Hono's c.json serializes monolithically via JSON.stringify→new Response(string) (hono context.js:375-381). Single ~66KB request ≈ 320MB string / ≥600MB peak; 100-query batch ≈ 13GB intermediates + multi-GB stringify target. Sync stringify blocks the event loop so the timeout middleware cannot preempt; hard OOM bypasses app.onError entirely. Same math applies to includeData once fat stored blobs exist (see companion cap finding fixed separately).
Fix direction: projected-size budget check before executing (topK×dim×bytes-per-float×batch vs configurable ceiling), and/or clamp effective topK when includeVectors=true, and/or stream-encode responses.