feat(agent-bff): map agent errors to the BFF error contract#1738
Open
nbouliol wants to merge 5 commits into
Open
feat(agent-bff): map agent errors to the BFF error contract#1738nbouliol wants to merge 5 commits into
nbouliol wants to merge 5 commits into
Conversation
1 new issue
|
|
Coverage Impact ⬆️ Merging this pull request will increase total coverage on Modified Files with Diff Coverage (2)
🤖 Increase coverage with AI coding...🚦 See full report on Qlty Cloud » 🛟 Help
|
Add mapAgentError() translating agent-client AgentHttpError failures into the BFF error envelope, plus the complete registry of BFF-local error factories the Slice-3 endpoints emit. Fixes PRD-670 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- unmapped agent error name now returns 500 mapping_error instead of a silent status fallback - extract the unmapped-name warn out of fallbackTypeByStatus (single responsibility) - use a named constant for the validation_error type - make the name-to-type test use an explicit table instead of deriving expectations from the map under test Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
886cec1 to
d9c89e7
Compare
…mapping - fall back to the outer AgentHttpError status when the JSON:API error object omits its own status, instead of hardcoding 400 - fall back to errors[0].message when detail is absent, before the generic default message Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…dies When the agent body is not a JSON error object, use AgentHttpError.responseText as the message source before the generic default, so plain-text or empty bodies still surface the agent-supplied text. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
JSON:API expresses errors[0].status as a string; a string status reached BffHttpError and was rejected by isSerializableError, downgrading a mapped 4xx to a generic 500. Coerce it to a number before constructing the error. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Context
Slice-3 BFF data/action endpoints (PRD-671..674) need one shared error layer producing the BFF envelope
{ error: { type, status, message, details? } }, so consumers branch onerror.type+error.status, never on a message substring. This ships first and is a hard dependency of every Slice-3 endpoint ticket.What this adds
src/http/agent-error-mapper.ts—mapAgentError(error, { logger }): BffHttpError:AgentHttpError) →network_error(502)agent_unavailable(503, normalized)errors[0]→ type from an explicit name registry (NotFoundError→not_found, …); status fromerrors[0].status, falling back to the outerAgentHttpError.status;messagefromdetail(thenmessage);detailsfromdatamapping_error(500) + anError-level log (an unrecognized agent error type is treated as a broken BFF mapping invariant, surfaced for an explicit registry entry rather than silently bucketed)Errorwhose message is a JSON{ errors: [...] }stringsrc/http/bff-local-errors.ts— the complete registry of BFF-local factories the Slice-3 endpoints emit:unknown_*(404),*_not_allowed(403),invalid_request(400),relation_field_not_supported(422),mapping_error(500),unsupported_action_result(501).package.json— adds@forestadmin/agent-client(the committed BFF→agent transport;AgentHttpErroris the mapper input).Produced
BffHttpErrorinstances flow through the existingerror-middlewareunchanged. No barrel exports: in-package endpoints import relatively.Notes / deviations from the ticket text
The ticket and the global spec were stale on three points; the implementation follows the actual code:
AgentHttpError(notError(JSON.stringify(...))); the string case is kept as a defensive fallback.data, notmeta/source;detailsis sourced fromdata.NotFoundError, notNotFound), so an explicit registry replaces literal snake_case.Deliberate contract choices (unspecified by the spec):
network_error=502 /agent_unavailable=503.mapping_error(500), not a status-based fallback: an unknown type is a broken mapping invariant and is logged for an explicit registry addition. This intentionally masks the agent’s original status for unrecognized names.Tests
test/http/agent-error-mapper.test.ts— registry coverage, JSON-in-message parse, outer-status fallback, message fallback, transport→502, 5xx→503, flat body→400, unmapped-name→500+log.test/http/bff-local-errors.test.ts— every factory + details.Full suite: 391/391 pass; build + lint clean.
Fixes PRD-670
🤖 Generated with Claude Code
Note
Map agent errors to the BFF error contract in
agent-bffagent-error-mapper.tswithmapAgentError, the main entrypoint that converts thrown errors (includingAgentHttpErrorand transport failures) into typedBffHttpErrorinstances.ValidationError→invalid_request) with a status-based fallback when the name is absent or unrecognized.agent_unavailable(503) and transport failures tonetwork_error(502).bff-local-errors.tswith factory functions for BFF-specific errors (e.g.unknownCollection,mappingError,unsupportedActionResult).mapping_errorand log an entry instead of forwarding the original error.Macroscope summarized d22a4c2.