Awesome-claude-code bug-root-cause-finder
Root cause analysis methods for PHP bugs. Provides 5 Whys technique, fault tree analysis, git bisect guidance, and stack trace parsing.
git clone https://github.com/dykyi-roman/awesome-claude-code
T=$(mktemp -d) && git clone --depth=1 https://github.com/dykyi-roman/awesome-claude-code "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/bug-root-cause-finder" ~/.claude/skills/dykyi-roman-awesome-claude-code-bug-root-cause-finder && rm -rf "$T"
skills/bug-root-cause-finder/SKILL.mdBug Root Cause Finder
Systematic methods for finding the true source of bugs, not just symptoms.
Core Principle: Symptom ≠ Cause
The location where an error manifests is rarely where the bug originates.
Error Location: OrderController::show() - NullPointerException Symptom Location: OrderRepository::find() - returns null Root Cause: OrderCreatedHandler - failed to persist order True Root Cause: RabbitMQ message lost due to missing ACK
Method 1: 5 Whys Technique
Ask "why" repeatedly until you reach the root cause.
Example Analysis
Bug: "Customer sees wrong order total"
- Why? → The total displayed is $0
- Why? →
returns 0Order::getTotal() - Why? →
collection is emptyOrderItem - Why? → Items weren't loaded from database
- Why? → Lazy loading failed due to closed EntityManager
Root Cause: EntityManager closed before accessing lazy-loaded collection
Fix: Eager load items in repository query, not lazy load
5 Whys Template
## 5 Whys Analysis **Bug Description:** [What user sees] 1. Why does [symptom] occur? → [First-level cause] 2. Why does [first-level cause] happen? → [Second-level cause] 3. Why does [second-level cause] happen? → [Third-level cause] 4. Why does [third-level cause] happen? → [Fourth-level cause] 5. Why does [fourth-level cause] happen? → [ROOT CAUSE] **Fix Location:** [File:line where fix should be applied] **Fix Type:** [Category: logic/null/boundary/race/resource/exception/type/sql/infinite]
Method 2: Fault Tree Analysis
Build a tree of all possible causes for a failure.
Fault Tree Structure
[FAILURE: Order total is $0] │ ├── [OR] Order has no items │ ├── [AND] Items not added during creation │ │ ├── Cart was empty │ │ └── Cart-to-Order mapping failed │ │ │ └── [AND] Items were deleted │ ├── Cascade delete triggered │ └── Manual deletion bug │ └── [OR] Items exist but total calculation wrong ├── Price is 0 │ ├── Product price not set │ └── Currency conversion failed │ └── Quantity is 0 ├── Validation missing └── Type coercion (string "0")
Fault Tree Investigation Order
- Start with most likely branches (based on code review)
- Add logging/debugging to verify each branch
- Eliminate branches systematically
- Focus on remaining possibilities
Method 3: Git Bisect
Find the exact commit that introduced a bug.
Git Bisect Steps
# 1. Start bisect git bisect start # 2. Mark current (broken) as bad git bisect bad # 3. Mark known good commit (e.g., last release) git bisect good v2.3.0 # 4. Git checks out middle commit - test it # Run your reproduction test php artisan test --filter=OrderTotalTest # 5. Mark result git bisect good # if test passes git bisect bad # if test fails # 6. Repeat until Git finds the culprit commit # Git will output: "abc123 is the first bad commit" # 7. Examine the commit git show abc123 # 8. End bisect git bisect reset
Automated Git Bisect
# Run automatically with test script git bisect start HEAD v2.3.0 git bisect run php artisan test --filter=OrderTotalTest
Git Bisect Tips
- Choose good boundaries: Bad = current, Good = last known working
- Use automated testing: Faster and more reliable
- Check for flaky tests: Bisect fails with inconsistent tests
- Look at the diff: Focus on changed lines in culprit commit
Method 4: Stack Trace Parsing
Extract actionable information from error traces.
PHP Stack Trace Structure
Fatal error: Uncaught TypeError: OrderService::calculateTotal(): Argument #1 ($items) must be of type array, null given, called in /app/src/Application/UseCase/CreateOrderUseCase.php on line 45 Stack trace: #0 /app/src/Application/UseCase/CreateOrderUseCase.php(45): OrderService->calculateTotal(NULL) #1 /app/src/Presentation/Api/OrderController.php(32): CreateOrderUseCase->execute(Object(CreateOrderCommand)) #2 /app/vendor/symfony/http-kernel/HttpKernel.php(163): OrderController->create(Object(Request)) #3 /app/vendor/symfony/http-kernel/HttpKernel.php(75): HttpKernel->handleRaw(Object(Request)) #4 /app/public/index.php(25): HttpKernel->handle(Object(Request)) #5 {main} thrown in /app/src/Domain/Service/OrderService.php on line 23
Key Information to Extract
| Element | Value | Meaning |
|---|---|---|
| Error Type | TypeError | Type mismatch bug |
| Message | Argument #1 must be array, null given | Null pointer issue |
| Thrown Location | OrderService.php:23 | Where error detected |
| Call Location | CreateOrderUseCase.php:45 | Where bad value passed |
| Root Investigation | CreateOrderUseCase.php:45 | Start here |
Stack Trace Analysis Steps
- Read error message - What type of error?
- Find thrown location - Where was error detected?
- Find call location - Where was bad value passed?
- Trace backward - How did bad value get there?
- Find origin - Where was value first set to bad state?
Common Stack Trace Patterns
Pattern: Null from Repository
#0 Repository->find() returns null #1 Service uses result without check #2 Controller calls service
→ Fix in #1: Add null check
Pattern: Type Coercion
#0 Method expects int, gets string #1 Request data not validated #2 Controller passes raw input
→ Fix in #1 or #2: Add validation/casting
Pattern: Missing Dependency
#0 Service->method() called #1 Container->get() fails #2 Dependency not registered
→ Fix: Register dependency in container
Method 5: Dependency Graph Analysis
Trace data flow through the application.
Data Flow Tracing
// Trace the flow of $orderId 1. Controller receives $orderId from Request 2. UseCase receives $orderId as Command property 3. Repository uses $orderId in SQL query 4. Database returns null (ID doesn't exist) 5. UseCase passes null to Service 6. Service throws NullPointerException
Dependency Questions
- Where does the value originate?
- What transformations does it undergo?
- Where is it validated?
- Where could it become invalid?
- Who else uses this value?
Call Graph Investigation
# Find all callers of a method grep -r "->calculateTotal(" src/ # Find all places where variable is set grep -r "\$items\s*=" src/ # Find all null assignments grep -r "= null" src/Domain/
Method 6: State Timeline Reconstruction
Rebuild the sequence of state changes.
Timeline Template
## State Timeline T0: Initial state - Order::status = DRAFT - Order::items = [] T1: AddItemToOrder executed - Order::items = [Item(id=1)] - Expected: status stays DRAFT ✓ T2: SubmitOrder executed - Order::status = SUBMITTED - Expected: items preserved ✓ T3: PaymentReceived event - Order::status = PAID - BUG: items cleared unexpectedly ✗ T4: GetOrder query - Returns Order with empty items - User sees $0 total Root Cause: PaymentReceived handler incorrectly reinitializes Order
Investigation Checklist
Before Starting
- Reproduce bug consistently
- Identify exact error message
- Note conditions when bug occurs
- Check if bug is environment-specific
During Investigation
- Parse stack trace for key locations
- Apply 5 Whys technique
- Build fault tree if multiple possible causes
- Use git bisect if recent regression
- Trace data flow from origin to error
After Finding Root Cause
- Verify fix addresses root cause, not symptom
- Check for similar bugs in related code
- Document root cause for team knowledge
- Consider if design change prevents recurrence
Quick Reference: Where to Look First
| Bug Type | First Investigation Point |
|---|---|
| Null pointer | Repository/Factory that creates the null |
| Wrong calculation | Input values, not calculation logic |
| Missing data | Event handler or background job |
| Intermittent failure | Shared state or race condition |
| After deployment | Git diff between versions |
| Only in production | Environment config or data |
| Only for some users | User-specific data or permissions |