Skip to content

feat(agent-bff): map agent errors to the BFF error contract#1738

Open
nbouliol wants to merge 5 commits into
mainfrom
feature/prd-670-map-agent-errors-to-the-bff-error-contract
Open

feat(agent-bff): map agent errors to the BFF error contract#1738
nbouliol wants to merge 5 commits into
mainfrom
feature/prd-670-map-agent-errors-to-the-bff-error-contract

Conversation

@nbouliol

@nbouliol nbouliol commented Jul 6, 2026

Copy link
Copy Markdown
Member

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 on error.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.tsmapAgentError(error, { logger }): BffHttpError:
    • transport failure (raw error, not an AgentHttpError) → network_error (502)
    • agent 5xx → agent_unavailable (503, normalized)
    • JSON:API errors[0] → type from an explicit name registry (NotFoundErrornot_found, …); status from errors[0].status, falling back to the outer AgentHttpError.status; message from detail (then message); details from data
    • unknown agent name → mapping_error (500) + an Error-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)
    • defensive parse of an Error whose message is a JSON { errors: [...] } string
  • src/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; AgentHttpError is the mapper input).

Produced BffHttpError instances flow through the existing error-middleware unchanged. 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:

  • agent-client throws a typed AgentHttpError (not Error(JSON.stringify(...))); the string case is kept as a defensive fallback.
  • Agent JSON:API errors carry data, not meta/source; details is sourced from data.
  • Agent error names are suffixed (NotFoundError, not NotFound), so an explicit registry replaces literal snake_case.

Deliberate contract choices (unspecified by the spec):

  • network_error=502 / agent_unavailable=503.
  • An unmapped agent error name resolves to 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-bff

  • Adds agent-error-mapper.ts with mapAgentError, the main entrypoint that converts thrown errors (including AgentHttpError and transport failures) into typed BffHttpError instances.
  • Maps JSON:API error bodies by agent error name (e.g. ValidationErrorinvalid_request) with a status-based fallback when the name is absent or unrecognized.
  • Normalizes agent 5xx responses to agent_unavailable (503) and transport failures to network_error (502).
  • Adds bff-local-errors.ts with factory functions for BFF-specific errors (e.g. unknownCollection, mappingError, unsupportedActionResult).
  • Risk: unmapped agent error names produce a 500 mapping_error and log an entry instead of forwarding the original error.

Macroscope summarized d22a4c2.

@linear-code

linear-code Bot commented Jul 6, 2026

Copy link
Copy Markdown

PRD-670

@qltysh

qltysh Bot commented Jul 6, 2026

Copy link
Copy Markdown

1 new issue

Tool Category Rule Count
qlty Structure Function with many returns (count = 5): mapAgentError 1

Comment thread packages/agent-bff/src/http/agent-error-mapper.ts Outdated
Comment thread packages/agent-bff/src/http/agent-error-mapper.ts Outdated
@qltysh

qltysh Bot commented Jul 6, 2026

Copy link
Copy Markdown

Qlty


Coverage Impact

⬆️ Merging this pull request will increase total coverage on main by 0.01%.

Modified Files with Diff Coverage (2)

RatingFile% DiffUncovered Line #s
New Coverage rating: A
packages/agent-bff/src/http/agent-error-mapper.ts98.3%97
New Coverage rating: A
packages/agent-bff/src/http/bff-local-errors.ts100.0%
Total98.8%
🤖 Increase coverage with AI coding...
In the `feature/prd-670-map-agent-errors-to-the-bff-error-contract` branch, add test coverage for this new code:

- `packages/agent-bff/src/http/agent-error-mapper.ts` -- Line 97

🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

Comment thread packages/agent-bff/src/http/agent-error-mapper.ts
nbouliol and others added 2 commits July 7, 2026 10:37
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>
@nbouliol nbouliol force-pushed the feature/prd-670-map-agent-errors-to-the-bff-error-contract branch from 886cec1 to d9c89e7 Compare July 7, 2026 08:38
…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>
Comment thread packages/agent-bff/src/http/agent-error-mapper.ts Outdated
…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>
Comment thread packages/agent-bff/src/http/agent-error-mapper.ts Outdated
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant