Skip to content

tristanpoland/lazy-errors

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

2 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Lazy Errors πŸ¦€βš‘

Crates.io License: MIT

A fast, accurate static analysis tool that detects lazy error handling patterns in Rust codebases. Help improve your code's robustness by identifying problematic uses of .unwrap(), .expect(), and other potentially dangerous error handling shortcuts.

🎯 What It Does

Lazy Errors scans your Rust project and identifies patterns that could lead to runtime panics or poor error handling:

  • .unwrap() - Panics if the value is an error
  • .expect() - Panics with a custom message
  • .unwrap_or() - Returns a fallback value
  • .unwrap_or_else() - Computes a fallback value
  • .unwrap_or_default() - Uses the default value
  • .ok()? - Discards error information
  • .err()? - Extracts error, discarding success

πŸš€ Installation

From Crates.io

cargo install lazy-errors

From Source

git clone https://github.com/tristanpoland/lazy-errors
cd lazy-errors
cargo install --path .

πŸ“– Usage

Basic Usage

# Scan current directory with default strictness (level 2)
lazy-errors .

# Scan specific directory
lazy-errors /path/to/your/rust/project

# Set strictness level (1-4)
lazy-errors . --strictness 4

# Show verbose output
lazy-errors . --verbose

# Exclude specific directories
lazy-errors . --exclude target,tests,examples

GitHub Actions Integration

# GitHub Actions mode with enhanced output
lazy-errors . --github-actions

# Exit with error code if issues found
lazy-errors . --fail-on-found

🎚️ Strictness Levels

Configure how aggressive the checking should be:

Level 1: Critical Only

lazy-errors . -s 1

Checks for:

  • .unwrap() - High risk of panics

Best for: Legacy codebases where you want to find the most dangerous patterns first.

Level 2: Standard (Default)

lazy-errors . -s 2

Checks for:

  • .unwrap() - High risk of panics
  • .expect() - Panics with messages

Best for: Most projects wanting to improve error handling without being overwhelmed.

Level 3: Comprehensive

lazy-errors . -s 3

Checks for:

  • .unwrap() - High risk of panics
  • .expect() - Panics with messages
  • .unwrap_or() - Uses fallback values
  • .unwrap_or_else() - Computes fallback values

Best for: Mature codebases aiming for robust error handling.

Level 4: Strict

lazy-errors . -s 4

Checks for:

  • .unwrap() - High risk of panics
  • .expect() - Panics with messages
  • .unwrap_or() - Uses fallback values
  • .unwrap_or_else() - Computes fallback values
  • .unwrap_or_default() - Uses default values
  • .ok()? - Discards error information
  • .err()? - Extracts errors

Best for: New projects or critical systems where error handling is paramount.

πŸ”§ Command Line Options

Option Short Description
--strictness -s Set strictness level (1-4, default: 2)
--verbose -v Show detailed output and statistics
--exclude -e Exclude directories (comma-separated)
--github-actions Output GitHub Actions annotations
--fail-on-found Exit with code 1 if issues found
--help -h Show help information
--version -V Show version information

πŸ“Š Example Output

Standard Output

❌ Found 3 issues in 5 files:

πŸ“„ src/main.rs
  42:18 - unwrap - let config = load_config().unwrap();
  67:31 - expect - fs::read_to_string(path).expect("Failed to read file");

πŸ“„ src/utils.rs  
  23:45 - unwrap_or - self.cache.get(key).unwrap_or(default_value);

Summary by function:
  unwrap: 1 occurrences
  expect: 1 occurrences
  unwrap_or: 1 occurrences

GitHub Actions Output

::warning file=src/main.rs,line=42,col=18::unwrap usage found: let config = load_config().unwrap();
::warning file=src/main.rs,line=67,col=31::expect usage found: fs::read_to_string(path).expect("Failed to read file");

🎯 Integration Examples

Pre-commit Hook

Add to .pre-commit-hooks.yaml:

repos:
  - repo: local
    hooks:
      - id: lazy-errors
        name: Check for lazy error handling
        entry: lazy-errors
        args: ['.', '--fail-on-found']
        language: system
        pass_filenames: false

GitHub Actions Workflow

name: Code Quality

on: [push, pull_request]

jobs:
  lazy-errors:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Install Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
      - name: Install lazy-errors
        run: cargo install lazy-errors
      - name: Check for lazy error handling
        run: lazy-errors . --github-actions --strictness 3

Cargo Make Integration

Add to Makefile.toml:

[tasks.check-lazy-errors]
description = "Check for lazy error handling patterns"
command = "lazy-errors"
args = [".", "--strictness", "3", "--verbose"]

🧠 Why This Matters

The Problem

// ❌ Dangerous - will panic in production
let config = std::env::var("CONFIG_PATH").unwrap();
let data = fs::read_to_string(config).unwrap();

// ❌ Better message, still panics
let port = std::env::var("PORT")
    .expect("PORT environment variable must be set");

Better Alternatives

// βœ… Proper error handling
let config = std::env::var("CONFIG_PATH")
    .map_err(|_| "CONFIG_PATH not set")?;
let data = fs::read_to_string(config)
    .map_err(|e| format!("Failed to read config: {}", e))?;

// βœ… Graceful fallback
let port = std::env::var("PORT")
    .unwrap_or_else(|_| "8080".to_string());

// βœ… Using Result properly
fn load_config() -> Result<Config, ConfigError> {
    let path = std::env::var("CONFIG_PATH")?;
    let contents = fs::read_to_string(path)?;
    toml::from_str(&contents).map_err(Into::into)
}

πŸ” How It Works

Lazy Errors uses Rust's syn crate to perform accurate AST-based analysis:

  1. Parse Rust source into Abstract Syntax Tree (AST)
  2. Visit method calls to identify error handling patterns
  3. Validate context to avoid false positives in comments/strings
  4. Report precise locations with line and column numbers

This approach ensures:

  • βœ… No false positives from comments or string literals
  • βœ… Accurate parsing of complex Rust syntax
  • βœ… Fast performance with proper caching
  • βœ… Reliable results across different code styles

🀝 Contributing

We welcome contributions! Here's how you can help:

Reporting Issues

  • Use our issue templates
  • Provide minimal reproduction cases
  • Include your Rust version and OS

Contributing Code

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Make your changes with tests
  4. Run the test suite: cargo test
  5. Submit a pull request

Development Setup

git clone https://github.com/tristanpoland/lazy-errors
cd lazy-errors
cargo build
cargo test

πŸ“œ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ™ Acknowledgments

  • The Rust community for excellent tooling and documentation
  • syn for robust Rust parsing
  • clap for CLI argument handling
  • All contributors and issue reporters

πŸ“š Further Reading

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages