Skip to content

feat(api): Every error is a Problem Details response (#364) - #376

Merged
bitbiter-dev merged 2 commits into
masterfrom
feat/364-problem-details
Oct 30, 2026
Merged

bitbiter-dev merged 2 commits into
masterfrom
feat/364-problem-details

Conversation

@bitbiter-dev

Copy link
Copy Markdown
Owner

Closes #364.

What changed

The remaining { error } bodies are now Problem Details (application/problem+json). Each one keeps today's text in detail and adds a stable code extension:

Site Status code errors field
Admin create user 422 / 409 invalid_username, invalid_email, username_taken, email_taken username / email
Admin patch / delete self 403 cannot_modify_self —
Admin create storage config 422 / 409 path_invalid, path_already_assigned, path_overlaps rootPath
GET /flashbacks/on-this-day bad date 400 invalid_date date
Must-change-password check 403 password_change_required —

Field failures are ValidationProblems whose errors hold the code under the request field. Registration has worked this way since #357.

AuthProblems and AuthErrorCodes are renamed to ApiProblems and ErrorCodes, because non-auth endpoints use them now.

Against the acceptance criteria

  • code, not type. The cases a client branches on carry code, and type is left at its default. That follows the decision in the owner's comment on feat(api): Every error is a Problem Details response #364, which says to reuse code rather than add a second identifier in type. The tests therefore assert code.
  • OpenAPI document unchanged. It was regenerated and nothing changed (scripts/derive-openapi.sh --check passes). These endpoints return untyped IResult, so their error responses aren't described yet. Describing them is feat(api): The OpenAPI document describes every response #365.
  • Account lock and rate limit. Retry-After on a locked account, and the 429 rate_limited response, are still asserted in AuthErrorContractTests.
  • Mutation testing. scripts/mutation-changed.sh scores 100.00% (70 killed, 0 survived).
  • invalid_username text. Admin create user's detail stays AuthMessages.InvalidUsername, while registration's comes from the username policy. That difference already existed and is carried over unchanged.

Tests

  • New HTTP-level AdminErrorContractTests cover every admin site. They assert status, application/problem+json, code, status, detail and the errors field against literal values.
  • The flashback and must-change-password tests now assert the same fields.
  • The assertions live in a shared ProblemAssertions helper.

Not in this PR

The existing ValidationProblems in WorkItemEndpoints and ProxySweepEndpoints carry no code. They were never { error } bodies, so they're noted on #365 instead.

🤖 Generated with Claude Code

bitbiter-dev and others added 2 commits October 30, 2026 16:29
The remaining { error } bodies become Problem Details with a stable
`code` extension and today's text in `detail`: admin user creation,
cannot-modify-self, storage config path rejections, the flashback date
and the must-change-password check. Field failures are ValidationProblems
keyed by the request field, as for registration.

Following the decision recorded on #364, the identifier a client branches
on is `code`, not `type`. AuthProblems and AuthErrorCodes become
ApiProblems and ErrorCodes, since they now serve non-auth endpoints.

The OpenAPI document is unchanged: these endpoints return untyped
IResult, and describing their responses is #365.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bitbiter-dev
bitbiter-dev merged commit 9306634 into master Oct 30, 2026
20 checks passed
@bitbiter-dev
bitbiter-dev deleted the feat/364-problem-details branch October 30, 2026 03:49
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.

feat(api): Every error is a Problem Details response

1 participant