How to File a Good Bug Report for Rust Projects

Use the provided issue template to document search terms, file checks, and a clear description of the problem and suggested fix.

The bug report that gets fixed

You found a bug. The code in the Rust Book doesn't compile. A crate panics on your machine. The compiler rejects syntax that looks correct. You open an issue on GitHub and type "It doesn't work." You hit submit.

Three weeks pass. No response. You check back. The issue is closed with "Cannot reproduce." You're frustrated. The maintainer is frustrated too. They get fifty issues a week. Three of them are gold. Forty-seven are noise. Your report got lost in the noise.

A good bug report is a reproducible script. It turns the maintainer's curiosity into a fix in under five minutes. You're not just complaining; you're handing them a loaded gun aimed at the bug. The goal is to make it easier for the maintainer to fix the bug than to close the issue.

Your report is either a gift or a chore. Make it a gift.

Anatomy of a title

The title is the first thing the maintainer reads. It's also the first thing future users see when they search for the same problem. A vague title buries your report. A precise title makes it a resource.

Bad titles:

  • "Bug"
  • "Help please"
  • "Error in chapter 9"
  • "Something is wrong"

Good titles:

  • "E0382 in ch09-00 example when moving Result"
  • "Panic in Vec::push with custom allocator on Windows"
  • "Typo in E0432 explanation breaks import path"

The title should contain the error code if there is one. It should mention the specific function, module, or section. It should describe the behavior, not the emotion. If the compiler gives you E0308 (mismatched types), put E0308 in the title. The maintainer can scan for that code instantly. If you're reporting a typo, mention the section and the nature of the error.

Your title is a search query for the future. Write it for the stranger, not yourself.

The search ritual

Before you write a single word, search. Duplicates are the number one waste of time in open source. The bug might already be fixed. The bug might be documented as "won't fix." The bug might have a workaround in a comment on a closed issue.

Use the project's issue tracker. Use GitHub's search bar. Search for keywords from the error message. Search for the file name. Search for the function name. Look at closed issues too. A closed issue often contains the fix or the explanation.

Check the main branch. If you're using a released version, the bug might be fixed in the development branch. Pull the latest code. Run the example again. If it works, you don't need to file a bug. You just need to update.

If you file a duplicate, the maintainer closes it instantly. You get no fix. You get no credit. You just added to the noise. Search thoroughly. If you can't find a duplicate, mention your search terms in the report. It proves you did the work.

The MCVE ritual

MCVE stands for Minimal Complete Verifiable Example. It's the smallest possible piece of code that still reproduces the bug. It's the heart of a good report.

Start with your code. Copy it into a new file. Comment out half of it. Does the bug persist? If yes, delete the commented half. If no, restore it and comment out the other half. Repeat until you can't remove anything without the bug disappearing.

Replace complex logic with literals. If fetch_data() causes the bug, replace it with vec![1, 2, 3]. If the bug persists, the function isn't the cause. Keep going. Remove dependencies. Remove modules. Remove traits. Strip it down to the bare metal.

Often, you'll find the bug yourself during this process. You'll realize you forgot a lifetime. You'll see you're moving a value twice. You'll notice a typo. If you find the bug, you can still file a report if the error message was confusing or the documentation was misleading. But you'll file it with much more precision.

The community respects the effort of reduction. An MCVE signals that you've done the hard work. Maintainers prioritize issues with MCVEs. They reward that effort with faster fixes.

// BAD: Too much code, hard to isolate the bug
use std::fs;
use std::io;
use std::path::Path;

fn process_file(path: &Path) -> io::Result<Vec<String>> {
    let content = fs::read_to_string(path)?;
    let lines: Vec<String> = content.lines().map(|l| l.to_string()).collect();
    // ... 50 lines of processing logic ...
    Ok(lines)
}

fn main() {
    let path = Path::new("data.txt");
    let result = process_file(path);
    println!("{:?}", result);
}

// GOOD: Reduced to the essential failure
fn main() {
    // The bug is actually here: moving `lines` twice
    let lines = vec!["a".to_string(), "b".to_string()];
    let _x = lines;
    let _y = lines; // E0382: use of moved value
}

Reduce until it hurts. Then reduce one more line.

Environment and context

Rust is sensitive to environment. The compiler version matters. The operating system matters. Feature flags matter. Your report must include the context.

Include your rustc --version output. Don't just say "latest." "Latest" is a moving target. A version number is a coordinate. It pins the bug to a specific state of the compiler. Copy the full output, including the commit hash and date.

Include your OS and architecture. Some bugs only appear on Windows. Some only appear on ARM. Some depend on the C library. Mention x86_64-unknown-linux-gnu or aarch64-apple-darwin.

If the bug depends on Cargo features, list them. Show the relevant part of Cargo.toml. If the bug depends on RUSTFLAGS, mention them. If the bug depends on a specific crate version, list the dependency.

The community calls this "pinning the environment." It prevents the maintainer from asking "What version are you on?" and waiting for a reply. You give them the answer upfront.

# Include this if the bug depends on features
[dependencies]
serde = { version = "1.0", features = ["derive"] }

# Include this if the bug depends on a specific toolchain
# rust-toolchain.toml
[toolchain]
channel = "nightly-2024-05-01"

Copy-paste-run. If the maintainer has to type, you failed.

Pitfalls and compiler errors

You skip the search. You file a duplicate. The maintainer closes it instantly. You didn't check the main branch. The bug was fixed yesterday. You file it anyway. The maintainer sees the commit hash and closes it.

You paste a hundred lines of code. The bug is in line 42, but you included the boilerplate for a web server. The maintainer has to debug your code to find the bug. They don't have time. They close the issue.

You report "It gives an error." The maintainer asks "Which one?" You reply with a screenshot. The maintainer can't copy the text. They have to type it manually. They close the issue. Report the error text. Include the error code if you have it. E0382 (use of moved value) is better than "move error." E0599 (no method named 'foo') is better than "method not found."

You get defensive when the maintainer asks for more info. You say "I already told you." You didn't. The maintainer needs a specific detail you missed. Respond quickly. Provide the info. The conversation is part of the fix.

You file a bug for a feature request. The maintainer closes it as "enhancement." You argue. The issue tracker is for bugs. Use discussions or a separate label for features. Check the project's contribution guidelines.

Treat the issue tracker as a shared workspace. Leave it cleaner than you found it.

Decision matrix

Use a bug report when you find a deviation from expected behavior, a typo that breaks code, or a compiler error on valid syntax. Use a discussion or forum post when you're confused about a concept but the code works as documented. Use a pull request when you have a fix ready and the project accepts contributions. Use a security advisory when the bug exposes private data, allows remote execution, or violates the project's security policy.

Where to go next