| Crates.io | error-location |
| lib.rs | error-location |
| version | 0.1.0 |
| created_at | 2026-01-13 21:03:01.123928+00 |
| updated_at | 2026-01-13 21:03:01.123928+00 |
| description | A lightweight utility for capturing and displaying error locations in Rust |
| homepage | |
| repository | https://github.com/TonyMarkham/error-location |
| max_upload_size | |
| id | 2041256 |
| size | 21,695 |
A lightweight utility for capturing and displaying error locations in Rust.
This crate provides a simple wrapper around std::panic::Location to make it easier to track where errors originate in your code. It's particularly useful when building custom error types with crates like thiserror.
std#[track_caller] attribute[file:line:column]Add this to your Cargo.toml:
[dependencies]
error-location = "0.1"
use error_location::ErrorLocation;
use std::panic::Location;
#[track_caller]
fn might_fail() -> Result<(), String> {
let location = ErrorLocation::from(Location::caller());
Err(format!("Something went wrong at {}", location))
}
fn main() {
match might_fail() {
Ok(_) => println!("Success!"),
Err(e) => eprintln!("Error: {}", e),
// Output: Error: Something went wrong at [src/main.rs:15:5]
}
}
thiserrorThe crate shines when used with thiserror for custom error types:
use error_location::ErrorLocation;
use std::panic::Location;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum MyError {
#[error("Database error at {location}: {message}")]
Database {
message: String,
location: ErrorLocation,
},
#[error("API error at {location}: {status}")]
Api {
status: u16,
location: ErrorLocation,
},
}
#[track_caller]
fn query_database() -> Result<String, MyError> {
Err(MyError::Database {
message: "Connection failed".to_string(),
location: ErrorLocation::from(Location::caller()),
})
}
#[track_caller]
fn call_api() -> Result<String, MyError> {
Err(MyError::Api {
status: 404,
location: ErrorLocation::from(Location::caller()),
})
}
fn main() {
match query_database() {
Ok(data) => println!("Data: {}", data),
Err(e) => eprintln!("Error: {}", e),
// Output: Error: Database error at [src/main.rs:34:5]: Connection failed
}
}
You can create helper functions to reduce boilerplate:
use error_location::ErrorLocation;
use std::panic::Location;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum AppError {
#[error("Error at {location}: {message}")]
WithLocation {
message: String,
location: ErrorLocation,
},
}
#[track_caller]
fn err_loc(message: impl Into<String>) -> AppError {
AppError::WithLocation {
message: message.into(),
location: ErrorLocation::from(Location::caller()),
}
}
#[track_caller]
fn do_work() -> Result<(), AppError> {
Err(err_loc("Work failed"))
}
The ErrorLocation struct uses Rust's #[track_caller] attribute and std::panic::Location to capture the file, line, and column where an error is created. This information is stored at compile time, resulting in zero runtime overhead for location tracking.
When you mark a function with #[track_caller] and call Location::caller(), Rust automatically provides the caller's location information. The ErrorLocation struct wraps this in a convenient, Display-friendly format.
The Display implementation formats locations as:
[file/path.rs:line:column]
For example:
[src/database/query.rs:42:10]
While std::panic::Location is available in the standard library, this crate provides:
ErrorLocation conveys intent better than raw LocationThis crate requires Rust 1.70 or later.
Licensed under either of:
at your option.
Contributions are welcome! Please feel free to submit a Pull Request.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.