Status: Decided Date: 2026-03-23
The workspace ships a first-party package, torrust-index-located-error,
whose sole purpose is to decorate errors with std::panic::Location
(file, line, column) so that error origins can be traced back to source
code. It does this through a LocatedError<E> wrapper that captures
#[track_caller] locations and formats them alongside the original
error message.
The package has a small surface — two public types (Located,
LocatedError) and a pair of Into impls — but it introduces several
costs:
- Maintenance overhead. A dedicated workspace member with its own
Cargo.toml,README.md, and test suite must be kept in sync with the rest of the crate. - Leaky abstraction.
LocatedErrorwraps every source error in anArc, which is unnecessary for errors that are never shared across threads. Callers must deal with a lifetime parameter ('a) and theArcindirection. - Incomplete picture.
Locationcaptures a single call-site, not a causal chain. In async code the real origin may be several.awaitpoints away, making the single location misleading. - Redundant with
tracing. The package already depends ontracingand emits atracing::debug!event inside theIntoimpl. Modern Rust convention is to use structuredtracingspans and events for exactly this kind of contextual metadata — the subscriber (e.g.tracing-subscriber) can be configured to capture file/line automatically viawith_file(true)andwith_line_number(true), with richer context (span trees, timing, fields) than a bareLocation.
The package is consumed in only two modules:
src/config/mod.rs— three error variants wrap aLocatedError.src/web/api/server/mod.rs— one error variant wraps aLocatedError.
| Option | Approach | Pros | Cons |
|---|---|---|---|
A. Keep located-error |
No change | Zero effort | Maintenance cost continues; incomplete context vs. tracing |
B. Replace with #[track_caller] in-line |
Remove package, use Location::caller() directly at each call-site |
No extra dependency | Still a single location; manual plumbing everywhere |
C. Replace with tracing spans/events |
Remove package, log errors with tracing::error! or tracing::warn! at the point of creation; rely on subscriber for file/line |
Full causal chain via span tree; zero custom error wrappers; idiomatic Rust | Requires subscriber configuration; slightly different log output |
D. Replace with error-stack or eyre |
Use a community error-context crate | Rich backtraces and attachments | Adds a new dependency; heavier than needed for this use case |
Option C — Remove torrust-index-located-error and rely on tracing
for error-origin context.
- The Rust ecosystem has converged on
tracingas the standard approach for structured diagnostics. Capturing file and line via the subscriber is zero-cost when disabled and richer than a manualLocationwhen enabled. - Removing the wrapper simplifies the error types in
configandweb::api::server— they can use plainArc<dyn Error + Send + Sync>or concrete error types, eliminating the lifetime parameter. - The
tracing::debug!call already present insideLocatedError'sIntoimpl proves the intent was always to log; the wrapper is just an intermediate step that can now be dropped.
- In each call-site that currently converts into a
LocatedError, emit atracing::error!(ortracing::warn!) event with the source error as a field. - Replace the
LocatedError<'static, dyn Error + Send + Sync>fields in error enums withArc<dyn Error + Send + Sync>(or a concrete type where possible). - Remove the
torrust-index-located-errordependency from the rootCargo.tomlworkspace members and the[dependencies]table. - Delete the
packages/located-error/directory. - Ensure the
tracing-subscriberconfiguration includes file/line metadata (already the case in the existing subscriber setup, or trivially enabled).
- Simpler error types. No lifetime parameter, no
Arcwrapping every error. - Better diagnostics.
tracingspans provide a full causal tree, not just a single source location. - Fewer workspace members. One less package to maintain, version, and test.
- Log format change. Error locations will appear in tracing output
rather than in the
Displayimpl of the error itself. Consumers that parsedLocatedError's string format will need to adapt.