Summary
In src/domain/search/providers/remote.ts, embedRemote()'s response.json() call sits outside the try/catch that wraps the fetch() call. Every other failure mode in this function (abort/timeout, network failure, non-2xx status, missing/wrong-shape embedding field, dimension mismatch) is normalized into a descriptive EngineError naming the endpoint — but a 200 OK response with a malformed/non-JSON body (e.g. an HTML error page from a misconfigured proxy in front of the embeddings endpoint) throws a raw uncaught SyntaxError instead, breaking the otherwise-consistent error contract of this remote API boundary.
Where
src/domain/search/providers/remote.ts, in embedRemote (originally line 128, now inline in the per-batch loop right after calling the extracted executeRemoteEmbeddingRequest helper):
const json = (await response.json()) as OpenAIEmbeddingResponse;
Origin
Flagged by titan-gauntlet audit of this file (rule 2, pillar I) with recommendation: "move response.json() inside error handling so a malformed body produces the same EngineError contract as every other failure path."
Why not fixed inline
Phase 13 of the titan-forge run scoped to this file was explicitly restricted to a pure behavior-preserving decomposition (split embedRemote into a request-executor + response-validator, extract-method only — see commit "refactor: split embedRemote into request-executor and response-validator in remote.ts"). Folding in this error-handling behavior change would have mixed a bug fix into a refactor commit and risked masking a real behavior change as "just a decomposition." Filing this issue per the project's scope-discipline rule instead of guessing at intent.
Suggested fix
Wrap const json = (await response.json()) as OpenAIEmbeddingResponse; in a try/catch (or fold it into the request-executor / a small helper) that re-throws a SyntaxError/parse failure as an EngineError with a message consistent with the other failure paths in this function, e.g.:
Remote embedding endpoint <url> returned a response that could not be parsed as JSON: <message>
Should be covered by a new test mocking fetch to resolve with a non-JSON body (e.g. new Response('<html>...</html>', { status: 200 })) and asserting embedRemote rejects with EngineError rather than SyntaxError.
Summary
In
src/domain/search/providers/remote.ts,embedRemote()'sresponse.json()call sits outside the try/catch that wraps thefetch()call. Every other failure mode in this function (abort/timeout, network failure, non-2xx status, missing/wrong-shapeembeddingfield, dimension mismatch) is normalized into a descriptiveEngineErrornaming the endpoint — but a200 OKresponse with a malformed/non-JSON body (e.g. an HTML error page from a misconfigured proxy in front of the embeddings endpoint) throws a raw uncaughtSyntaxErrorinstead, breaking the otherwise-consistent error contract of this remote API boundary.Where
src/domain/search/providers/remote.ts, inembedRemote(originally line 128, now inline in the per-batch loop right after calling the extractedexecuteRemoteEmbeddingRequesthelper):Origin
Flagged by titan-gauntlet audit of this file (rule 2, pillar I) with recommendation: "move
response.json()inside error handling so a malformed body produces the sameEngineErrorcontract as every other failure path."Why not fixed inline
Phase 13 of the titan-forge run scoped to this file was explicitly restricted to a pure behavior-preserving decomposition (split
embedRemoteinto a request-executor + response-validator, extract-method only — see commit "refactor: split embedRemote into request-executor and response-validator in remote.ts"). Folding in this error-handling behavior change would have mixed a bug fix into a refactor commit and risked masking a real behavior change as "just a decomposition." Filing this issue per the project's scope-discipline rule instead of guessing at intent.Suggested fix
Wrap
const json = (await response.json()) as OpenAIEmbeddingResponse;in a try/catch (or fold it into the request-executor / a small helper) that re-throws aSyntaxError/parse failure as anEngineErrorwith a message consistent with the other failure paths in this function, e.g.:Should be covered by a new test mocking
fetchto resolve with a non-JSON body (e.g.new Response('<html>...</html>', { status: 200 })) and assertingembedRemoterejects withEngineErrorrather thanSyntaxError.