Skip to content

Commit 20ab763

Browse files
committed
Merge #852: refactor!: replace ServiceError god enum with domain-scoped error types (ADR-T-006)
19ad039 fix: improve error fidelity across From impls and messages (Peer Cat) f51406b feat: add 188 crate-level tests for the domain error system (ADR-T-006 Phase 4) (Peer Cat) f231c6c refactor!: replace ServiceError god enum with domain-scoped error types (ADR-T-006) (Peer Cat) 0816d65 refactor(errors): extract CategoryTagError from ServiceError (Peer Cat) a55fc2c refactor: standardise error derives on thiserror (ADR-T-006 Phase 0) (Peer Cat) Pull request description: ### Summary Replace the monolithic 41-variant `ServiceError` enum with four domain-scoped error types — `AuthError`, `UserError`, `TorrentError`, and `CategoryTagError` — each with co-located HTTP status-code mapping. A thin `ApiError` wrapper unifies them at the handler boundary. A 188-test crate-level suite locks down the new error contracts. Full rationale, migration plan, and testing acceptance criteria are documented in ADR-T-006. ### Motivation `ServiceError` had grown into a god enum where every service function could theoretically return any of 41 variants. Nine `From` impls silently erased original error causes into `InternalServerError` via `eprintln!`, and a monolithic match block mapped variants to HTTP status codes far from where the errors were defined. This made it impossible to know at the type level which errors a given service call could actually produce. ### What changed **Phase 0 — Prerequisite cleanup** (`a55fc2c`) - Standardised all error derives from `derive_more` and hand-written impls to `thiserror` - Replaced all `eprintln!` in `From` impls with structured `tracing::error!` calls - Implemented the `Error` trait on cache error types that previously only derived `Debug` - Removed the unused `anyhow` dependency **Phase 1 — Extract domain errors** (`430a06d`, `3b715a0`) - Introduced `AuthError` (13 variants: JWT, password, authorization) - Introduced `UserError` (21 variants: registration, profile, banning) - Introduced `TorrentError` (~24 variants: upload, listing, tracker interaction) - Retained `CategoryTagError` (extracted first as a proving ground) - Each domain error has a `status_code()` method and typed `From` impls for lower-level errors **Phase 2 — `ApiError` wrapper** (`3b715a0`) - `ApiError` wraps all four domain errors via `#[from]` and implements `IntoResponse` - Handlers spanning multiple domains use `ApiError` as their error type **Phase 3 — Cleanup** (`3b715a0`) - Removed `ServiceError` enum and `ServiceResult` type alias - Removed `http_status_code_for_service_error()` and `map_database_error_to_service_error()` free functions - Removed `IntoResponse for database::Error` **Phase 4 — Crate-level test suite** (`f51406b`) - 188 tests in errors covering ADR-T-006 §1–§4: - `auth_error.rs` — 29 tests (status codes, display, `From` impls) - `user_error.rs` — 54 tests - `torrent_error.rs` — 73 tests - `category_tag_error.rs` — 24 tests - `api_error.rs` — 8 tests (`status_code`/`Display` delegation) - Added Testing Acceptance Guide to ADR-T-006 (§1–§7) documenting requirements for future error variants - Fixed four "nota" → "not a" typos in torrent request error messages ### Breaking changes All public service function signatures now return `Result<T, DomainError>` instead of `Result<T, ServiceError>`. ### What did NOT change - The HTTP response shape (`{"error": "..."}`) is unchanged - No new crate dependencies (switched from `derive_more::Error` to `thiserror`, removed `anyhow`) - No behavioural changes — all existing tests pass ### Stats - 40 files changed, +2699 / −480 lines - Primary file: `errors.rs` (+426 / −223) - New: `006-error-system-refactor.md` (630 lines) - New: errors (1,168 lines across 5 test modules) ### Testing - `cargo test --workspace --all-targets --all-features` ✅ - `cargo test --workspace --all-features --doc` ✅ - `cargo clippy --workspace --all-targets --all-features` ✅ - `--no-default-features` build ✅ ACKs for top commit: peer-cat: ACK 19ad039 da2ce7: ACK 19ad039 Tree-SHA512: 2aa79a6b30f46b49c4dea268a86db89559eb71b8c78b66972d14eb1667c1ab418330c1480327b4bb72ee5ba5adb5b18c0be526f54a95077f669109ff76bbf27a
2 parents 6749e87 + 19ad039 commit 20ab763

40 files changed

Lines changed: 2720 additions & 485 deletions

AGENTS.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ Be mindful to at least do a quick spot-test with `--no-default-features`,
99
and to try building the docs and running the doc-tests.
1010

1111
When testing, also run the tests in `--release` mode to check that this
12-
works. Run the tests in debug mode with `CARGO_PROFILE_DEV_OPT_LEVEL=3`;
13-
otherwise it is just too slow. You can turn off the optimisation if a bug
14-
is found and you need backtracing.
12+
works. The dev profile already sets `opt-level = 3` in `Cargo.toml`,
13+
so debug builds are fast by default. If you need full backtraces for
14+
debugging, temporarily override with `CARGO_PROFILE_DEV_OPT_LEVEL=0`.
1515

1616
When working inside a package, prefer running only the `--package` tests,
1717
as the whole-project tests are slow to run. (Occasionally run the whole

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- ADR-T-006: Document rationale for error system refactor.
13+
- 188 crate-level tests for the domain error system (`src/tests/errors/`):
14+
status-code mapping, display messages, `From` impl coverage, and
15+
`ApiError` delegation (ADR-T-006 §1–§4).
16+
17+
### Changed
18+
19+
- **BREAKING:** Replace `ServiceError` (41 variants) and `ServiceResult` with
20+
domain-scoped error enums: `AuthError`, `UserError`, `TorrentError`,
21+
`CategoryTagError`, and a thin `ApiError` wrapper (ADR-T-006).
22+
- Service functions now return domain-specific `Result<T, DomainError>` instead
23+
of `Result<T, ServiceError>`.
24+
- Each domain error co-locates its HTTP status-code mapping via a
25+
`status_code()` method.
26+
- Error `From` impls use `tracing::error!` instead of `eprintln!`.
27+
- Standardise all error derives on `thiserror`.
28+
29+
### Removed
30+
31+
- `ServiceError` enum and `ServiceResult` type alias from `src/errors.rs`.
32+
- `http_status_code_for_service_error` and `map_database_error_to_service_error`
33+
helper functions.
34+
- `IntoResponse` impl for `database::Error` (now handled by domain errors).
35+
1036
## [4.0.0] - 2026-03-23
1137

1238
### Added

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,15 @@ version = "4.0.0-develop"
3535
[features]
3636
default = []
3737

38+
[profile.dev]
39+
opt-level = 3
40+
3841
[profile.dev.package.sqlx-macros]
3942
opt-level = 3
4043

4144
[dependencies]
4245
torrust-index-render-text-as-image = { version = "0.1.0", path = "packages/render-text-as-image" }
4346

44-
anyhow = "1"
4547
argon2 = "0"
4648
async-trait = "0"
4749
axum = { version = "0", features = ["multipart"] }
@@ -52,7 +54,7 @@ camino = { version = "1", features = ["serde"] }
5254
casbin = "2"
5355
chrono = { version = "0", default-features = false, features = ["clock"] }
5456
clap = { version = "4", features = ["derive", "env"] }
55-
derive_more = { version = "2", features = ["display", "error"] }
57+
derive_more = { version = "2", features = ["display"] }
5658
email_address = "0"
5759
figment = { version = "0", features = ["env", "test", "toml"] }
5860
futures = "0"

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ The following services are provided by the default configuration:
126126
- [ADR-T-003: Preparing for Rust Edition 2024](adr/003-edition-2024-preparation.md) — Pin dependencies to avoid edition-2024-only crates while the workspace remains on edition 2021; raise MSRV to 1.83.
127127
- [ADR-T-004: Remove `located-error` Package](adr/004-remove-located-error.md) — Replace the `torrust-index-located-error` wrapper with `tracing` for error context.
128128
- [ADR-T-005: Migrate to Rust Edition 2024](adr/005-edition-2024.md) — Migrate the entire workspace to `edition = "2024"` and raise the MSRV to 1.85.
129+
- [ADR-T-006: Refactor the Error System](adr/006-error-system-refactor.md) — Replace the 41-variant `ServiceError` god enum with domain-scoped error enums (`AuthError`, `UserError`, `TorrentError`, `CategoryTagError`) and a thin `ApiError` wrapper.
129130

130131
## Contributing
131132

0 commit comments

Comments
 (0)