rust-debugging
Skill0 starsChanged 35 days agoMITView on GitHub
Use when debugging Rust code or fixing errors.
- Installs packages
2 other projects use a version of this.
Adopted by
Most recently taken up by
- po4yka/rust-skillstheir own version, first seen Nov 2, 2026
- Dankosik/rust-cli-skillstheir own version, first seen Sep 8, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- po4yka/rust-skills★ 5same name
- Dankosik/rust-cli-skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository15 other files it gives its agents.
- AGENTS.mdAGENTS.md
- rustoriaSkill
- rust-dependenciesSkill
- rust-fundamentalsSkill
- rust-axumSkill
- rust-clapSkill
- rust-dieselSkill
- rust-ratatuiSkill
- rust-rayonSkill
- rust-serdeSkill
- rust-tokioSkill
- rust-productionSkill
- rust-code-auditSkill
- rust-stdSkill
- rust-unsafe-checkerSkill
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 2 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 16
Fix: Ensure immutable borrows are dropped before mutable borrows:
- Distinctive: line 71
Fix: Add trait bounds or use concrete types:
- Very specific: line 91
Fix: Check types match, use into(), as, or From:
- Very specific: line 271
Understand the type: - use dbg!, std::any::type_name, or a deliberate type error to see what the compiler actually inferred.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Rust Debugging Guide
Compiler Errors
1. Borrow Checker Errors
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutableFix: Ensure immutable borrows are dropped before mutable borrows:
// WRONG
let mut x = 5;
let r1 = &x;
let r2 = &mut x; // ERROR: r1 still alive
println!("{r1}");
// RIGHT
let mut x = 5;
let r1 = &x;
println!("{r1}"); // last use of r1
let r2 = &mut x; // OK: r1 no longer used
*r2 += 1;2. Lifetime Errors
error[E0515]: cannot return reference to local variableFix: return owned data. A &'static reference can't point at a local — locals are dropped when the function
returns. The real options:
- Return an owned value (
String,Vec, ...) — almost always the right answer. - Return a reference to a genuine
static/constitem. Box::leakto promote an owned value to&'static mut— permanently leaks memory until process exit; rarely appropriate.
// WRONG
fn bad() -> &str {
let s = String::from("hello");
&s // ERROR: s dropped at end of function
}
// RIGHT: return owned data
fn good() -> String {
String::from("hello")
}
// RIGHT (when you truly need &'static): a real static
static GREETING: &str = "hello";
fn greeting() -> &'static str {
GREETING
}3. Trait Bound Errors
error[E0277]: the trait bound `T: Clone` is not satisfiedFix: Add trait bounds or use concrete types:
// WRONG
fn process<T>(item: T) -> T {
item.clone() // ERROR: T might not be Clone
}
// RIGHT
fn process<T: Clone>(item: T) -> T {
item.clone()
}4. Type Mismatch
error[E0308]: mismatched typesFix: Check types match, use into(), as, or From:
let x: i32 = 5;
let y: i64 = x.into(); // OK
let z: i64 = x as i64; // OK5. Mutating While Iterating (Iterator Invalidation)
In C++, pushing into a vector during iteration is a runtime iterator-invalidation bug. Rust turns it into a compile error (E0502/E0499):
// Fragment — `vec: Vec<T>` where `T: Clone`.
// WRONG (does not compile)
for item in &vec {
vec.push(item.clone()); // ERROR: can't borrow vec mutably while borrowed
}
// RIGHT: collect first, then extend
let new_items: Vec<_> = vec.iter().cloned().collect();
vec.extend(new_items);Runtime Debugging
1. println! Debugging
println!("DEBUG: value = {:?}", value);
println!("DEBUG: struct = {:#?}", my_struct); // pretty print2. dbg! Macro
let x = 5;
let y = dbg!(x * 2); // Prints: [src/main.rs:2:5] x * 2 = 103. Logging with tracing
// Fragment — `db`, `User`, and the error type are placeholders for your code.
use tracing::{debug, info, instrument};
#[instrument]
async fn fetch_user(id: u64) -> Result<User> {
debug!("Fetching user {id}");
let user = db.fetch(id).await?;
info!("Fetched user: {user:?}");
Ok(user)
}4. Debugger (GDB/LLDB)
# Build with debug info (default for the dev profile)
cargo build
# Run under GDB (rust-gdb ships with rustup and adds Rust pretty-printers)
rust-gdb target/debug/myapp
# or plain: gdb target/debug/myapp
# LLDB (rust-lldb also ships with rustup)
rust-lldb target/debug/myapp5. VS Code Debugging
// .vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug",
"program": "${workspaceFolder}/target/debug/myapp",
"args": [],
"cwd": "${workspaceFolder}"
}
]
}Common Runtime Bugs and Fixes
1. Mutex Held Across .await
// Fragment — `std_mutex: std::sync::Mutex<T>` and `some_async()` are placeholders.
// WRONG: holding a std MutexGuard across .await
let guard = std_mutex.lock().unwrap();
some_async().await; // `guard` is !Send, so this future can't be spawned on the
// multi-threaded runtime (compile error). If it compiles
// (e.g. block_on / current_thread), other tasks needing the
// lock are starved while the holder is suspended — and a
// second lock attempt from the same task deadlocks it
// (std Mutex is not reentrant).
drop(guard);
// RIGHT: keep the critical section short — drop the guard BEFORE .await
let snapshot = {
let guard = std_mutex.lock().unwrap(); // handle poisoning in real code
(*guard).clone() // clone the inner value (T: Clone), not the guard
}; // guard dropped here
some_async().await;
println!("snapshot: {snapshot:?}");This is usually contention/starvation, not a true deadlock — unless the same task re-locks (non-reentrant mutex)
or two tasks acquire two mutexes in opposite orders. If the guard genuinely must live across .await, use
tokio::sync::Mutex (its guard is Send) — but held-across-await guards serialize tasks, so contention becomes a
throughput bottleneck. See the rust-tokio skill.
2. Integer Overflow
// WRONG: Panics in debug, wraps in release
let x: u8 = 255;
let y = x + 1; // PANIC in debug!
// RIGHT: Use wrapping_add or checked_add
let y = x.wrapping_add(1); // 0
let y = x.checked_add(1); // None3. Unwrap on None/Err
// Fragment — `some_option: Option<T>`, `some_result: Result<T, E>`, inside a
// function returning Result for the `?` line.
// WRONG: Panics
let x = some_option.unwrap();
let y = some_result.unwrap();
// RIGHT: Handle gracefully
let x = some_option.unwrap_or_default();
let y = some_result?; // propagate error4. Async Blocking
// WRONG: Blocking call inside async — stalls the whole worker thread
async fn bad() {
std::thread::sleep(std::time::Duration::from_secs(1));
}
// RIGHT: Async sleep yields to the runtime
async fn good() {
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
}Debugging Tools
| Tool | Purpose |
dbg! | Quick value inspection |
println! | Simple logging |
tracing | Structured logging |
gdb/lldb | Step-through debugging |
cargo test | Unit testing |
cargo clippy | Linting |
cargo fmt | Formatting |
cargo flamegraph | Performance profiling |
cargo asm | Assembly inspection |
cargo asm is provided by the cargo-show-asm plugin — cargo install cargo-show-asm first. cargo flamegraph
likewise needs cargo install flamegraph (plus perf on Linux or DTrace on macOS).
Debugging Workflow
- Read the whole diagnostic - rustc emits notes, secondary spans, and "help:" lines; the primary span often
marks the use site, not the root cause (E0502 reports the second borrow, not the live
r1). - Understand the type - use
dbg!,std::any::type_name, or a deliberate type error to see what the compiler actually inferred; most "wrong lifetime" bugs are really unexpected derefs or clones. - Isolate the question -
cargo checkfor compile errors,cargo testfor behavior,cargo buildfor profile-specific issues; cut the repro down until one command flips the result. - Fix and verify - re-run the failing command first, then
cargo testand clippy to catch the second-order breakage (a borrow fix often surfaces an unused-mut or dead-code warning).
When to Use
- Compiler errors (borrow checker, lifetimes, traits)
- Runtime panics
- Contention and deadlocks in async code
- Performance issues
- Logic bugs
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

