Plus actix defaults: the Claims extractor's 401 is text "Bad token"; query/path parse failures are actix's text 400.
10 sites send format!("{:?}", e) to the client (mostly duplicates.rs), which can include SQL and library paths.
Contract
{"error":"Tag name must not be empty","code":"invalid_tag_name","details":{}}
error: English, safe to show a user as is. The server knows best what went wrong; clients may translate known codes into their own wording.
code: stable snake_case id for clients to branch on instead of the status alone.
details (optional): structured extras. Existing top-level extras (existing_tag on tag rename 409) stay during migration for compatibility.
Unexpected errors: 500, code: "internal", a generic message. The detail is logged, never sent.
Plan
ApiError type (ResponseError) + From<anyhow::Error>; JSON/query/path extractor configs, Claims 401, default 404 for unknown routes all emit the contract; replace into_http_internal_err; move tags and enhance onto it; fix the {:?} leaks. Tests pin the shape.
Migrate the remaining modules, plain-text ones first: faces, handlers/image, duplicates, then the rest.
Error responses come in five shapes today, so clients can't show useful messages or branch reliably:
| Shape | Sites |
|---|---|
| JSON `{"error": msg}` | 144 (+ the global JSON-body handler) |
| JSON `{"error", "code"}` | Enhance only |
| Plain text body | 78 (faces 27, handlers/image 19, duplicates 11, files, libraries, versions, video, memories) |
| Plain text from `into_http_internal_err` | 11 (anyhow error text) |
| Empty body | ~95 (`.finish()` / bare builder), incl. login 401 |
Plus actix defaults: the `Claims` extractor's 401 is text "Bad token"; query/path parse failures are actix's text 400.
**10 sites send `format!("{:?}", e)` to the client** (mostly `duplicates.rs`), which can include SQL and library paths.
## Contract
```json
{ "error": "Tag name must not be empty", "code": "invalid_tag_name", "details": { } }
```
- `error`: English, safe to show a user as is. The server knows best what went wrong; clients may translate known codes into their own wording.
- `code`: stable snake_case id for clients to branch on instead of the status alone.
- `details` (optional): structured extras. Existing top-level extras (`existing_tag` on tag rename 409) stay during migration for compatibility.
- Unexpected errors: 500, `code: "internal"`, a generic message. The detail is logged, never sent.
## Plan
1. `ApiError` type (`ResponseError`) + `From<anyhow::Error>`; JSON/query/path extractor configs, `Claims` 401, default 404 for unknown routes all emit the contract; replace `into_http_internal_err`; move `tags` and `enhance` onto it; fix the `{:?}` leaks. Tests pin the shape.
2. Migrate the remaining modules, plain-text ones first: `faces`, `handlers/image`, `duplicates`, then the rest.
Client side: FileViewer-React issue (ApiError reads `code` + message).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Error responses come in five shapes today, so clients can't show useful messages or branch reliably:
{"error": msg}{"error", "code"}into_http_internal_err.finish()/ bare builder), incl. login 401Plus actix defaults: the
Claimsextractor's 401 is text "Bad token"; query/path parse failures are actix's text 400.10 sites send
format!("{:?}", e)to the client (mostlyduplicates.rs), which can include SQL and library paths.Contract
error: English, safe to show a user as is. The server knows best what went wrong; clients may translate known codes into their own wording.code: stable snake_case id for clients to branch on instead of the status alone.details(optional): structured extras. Existing top-level extras (existing_tagon tag rename 409) stay during migration for compatibility.code: "internal", a generic message. The detail is logged, never sent.Plan
ApiErrortype (ResponseError) +From<anyhow::Error>; JSON/query/path extractor configs,Claims401, default 404 for unknown routes all emit the contract; replaceinto_http_internal_err; movetagsandenhanceonto it; fix the{:?}leaks. Tests pin the shape.faces,handlers/image,duplicates, then the rest.Client side: FileViewer-React issue (ApiError reads
code+ message).