arabelatso/error-explanation-generator
Explains test failures and provides actionable debugging guidance. Use when tests fail (unit, integration, E2E), builds fail, or code throws errors. Analyzes error messages, stack traces, and test output to identify root causes and suggest concrete fixes. Handles pytest, jest, junit, mocha, vitest, selenium, cypress, playwright, and other testing frameworks across Python, JavaScript/TypeScript, Java, Go, and other languages.
npx skills add https://github.com/ArabelaTso/Skills-4-SE --skill error-explanation-generator
Analyze test failures and provide clear explanations with actionable fixes.
This skill helps debug failed tests by:
Collect all relevant information:
Essential Information:
Additional Context (if available):
How to gather:
# Python pytest
pytest -v --tb=long
# JavaScript/TypeScript jest
npm test -- --verbose
# Java junit
mvn test -X
# Go tests
go test -v
Identify the error category using references/error_patterns.md:
Common Categories:
10. Flaky Test Issues - Intermittent failures
Pull out critical details:
From Error Message:
From Stack Trace:
Example Extraction:
FAILED tests/test_user.py::test_create_user - AssertionError: assert 201 == 200
Extracted:
tests/test_user.pytest_create_userAssertionError200201Analyze why the error occurred:
Questions to Ask:
Common Root Causes:
Structure the explanation clearly:
## Error Summary
[One-sentence description of what went wrong]
## What Happened
[Explain the error in plain language]
**Expected:** [What the test expected to happen]
**Actual:** [What actually happened]
## Root Cause
[Explain why this happened - the underlying issue]
## How to Fix
### Option 1: [Most likely fix] ⭐
[Specific code change or action to take]
// Before
[problematic code]
// After
[fixed code]
**Why this works:** [Brief explanation]
### Option 2: [Alternative fix]
[Another possible solution if Option 1 doesn't apply]
## Verification
[How to verify the fix works]
[command to run test]
## Prevention
[How to avoid this error in the future]
Provide actionable guidance:
If fix is clear:
If diagnosis needs more info:
If issue is environmental:
Error Output:
FAILED tests/test_calculator.py::test_divide - AssertionError: assert 2.5 == 2
Analysis:
## Error Summary
Test expected integer division but got float division result.
## What Happened
**Expected:** `2` (integer)
**Actual:** `2.5` (float)
The test `test_divide` called a divide function with arguments that produce
a decimal result (e.g., 5 / 2 = 2.5) but expected an integer result.
## Root Cause
The implementation uses true division (`/`) which returns floats in Python 3,
but the test expects integer division behavior.
## How to Fix
### Option 1: Update implementation to use integer division ⭐
def divide(a, b):
return a / b
def divide(a, b):
return a // b # Integer division
**Why this works:** The `//` operator performs floor division, returning
integers when both operands are integers.
### Option 2: Update test to expect float result
assert divide(5, 2) == 2
assert divide(5, 2) == 2.5
Use this if float division is the intended behavior.
## Verification
pytest tests/test_calculator.py::test_divide -v
## Prevention
- Clarify division requirements in function documentation
- Use type hints: `def divide(a: int, b: int) -> int:`
- Add test cases for both integer and float division scenarios
Error Output:
TypeError: Cannot read property 'name' of undefined
at getUserName (src/user.js:5:20)
at Object.<anonymous> (tests/user.test.js:10:22)
Analysis:
## Error Summary
Attempted to access property 'name' on undefined user object.
## What Happened
**Expected:** User object with 'name' property
**Actual:** `undefined`
Function `getUserName()` tried to access `.name` property on a value that
was undefined, causing a runtime error.
## Root Cause
The user object passed to `getUserName()` was undefined. This commonly
happens when:
- Function called without argument
- Async data not yet loaded
- Database/API query returned no result
## How to Fix
### Option 1: Add null/undefined check ⭐
// Before
function getUserName(user) {
return user.name;
}
// After
function getUserName(user) {
if (!user) {
return null; // or throw error, or return default
}
return user.name;
}
**Why this works:** Defensively handles cases where user might be undefined.
### Option 2: Fix the test to provide valid user object
// Before
const name = getUserName(); // Called without argument
// After
const name = getUserName({ name: 'Alice', id: 1 });
### Option 3: Use optional chaining (modern JS)
function getUserName(user) {
return user?.name ?? 'Unknown';
}
## Verification
npm test -- user.test.js
## Prevention
- Add input validation to functions
- Use TypeScript for type safety
- Define clear function contracts
- Use optional chaining for property access
Error Output:
Timed out retrying after 4000ms: Expected to find element: [data-testid="submit-btn"],
but never found it.
Analysis:
## Error Summary
Test couldn't find submit button within timeout period.
## What Happened
**Expected:** Element with `data-testid="submit-btn"` to appear on page
**Actual:** Element never appeared within 4 seconds
## Root Cause
Possible reasons:
1. Element takes longer than 4s to render
2. Element has different selector/ID
3. Element only appears under certain conditions
4. JavaScript error preventing element from rendering
## How to Fix
### Option 1: Increase timeout for slow-loading elements ⭐
// Before
cy.get('[data-testid="submit-btn"]').click();
// After
cy.get('[data-testid="submit-btn"]', { timeout: 10000 }).click();
### Option 2: Wait for prerequisite conditions
// Wait for page to fully load first
cy.get('[data-testid="form-container"]').should('be.visible');
cy.get('[data-testid="submit-btn"]').click();
### Option 3: Check selector is correct
Inspect the page to verify:
// Verify element exists with different selector
cy.get('button[type="submit"]').click();
## Verification
npx cypress run --spec "cypress/e2e/form.cy.js"
## Debugging Steps
1. **Add screenshot on failure:**
cy.screenshot('before-submit-btn');
cy.get('[data-testid="submit-btn"]').click();
2. **Check browser console:**
cy.window().then((win) => {
console.log(win.document.body.innerHTML);
});
3. **Verify element in browser:**
Run test in headed mode: `npx cypress open`
## Prevention
- Use appropriate timeouts for async operations
- Add explicit waits for dynamic content
- Verify selectors match actual DOM
- Test with network throttling to catch timing issues
Error Output:
E AssertionError: Expected call: send_email('[email protected]', 'Welcome')
E Actual calls: []
Analysis:
## Error Summary
Mock expected a function call that never happened.
## What Happened
**Expected:** `send_email()` to be called with specific arguments
**Actual:** `send_email()` was never called
## Root Cause
The code being tested didn't call the mocked function. Common reasons:
- Different code path executed (conditional logic)
- Function called with different arguments
- Function called on different object instance
- Mock not properly configured
## How to Fix
### Option 1: Verify code path is reached ⭐
def test_registration_sends_email(mocker):
mock_send = mocker.patch('app.email.send_email')
result = register_user('[email protected]')
assert result.success, "Registration failed, email won't be sent"
mock_send.assert_called_once_with('[email protected]', 'Welcome')
### Option 2: Check mock target path
mocker.patch('app.email.send_email')
mocker.patch('app.user.send_email') # if user.py imports send_email
### Option 3: Relax assertion constraints
mock_send.assert_called_once_with('[email protected]', 'Welcome')
assert mock_send.called, "send_email was never called"
mock_send.assert_called()
args = mock_send.call_args[0]
assert args[0] == '[email protected]'
## Verification
pytest tests/test_registration.py::test_registration_sends_email -v
## Debugging Steps
Print actual calls to see what happened:
print(f"Mock called: {mock_send.called}")
print(f"Call count: {mock_send.call_count}")
print(f"Call args: {mock_send.call_args_list}")
## Prevention
- Mock at the point of use, not definition
- Verify code paths with unit tests first
- Use `assert mock.called` before checking arguments
- Print mock call history when debugging
Common error patterns:
AssertionError - Failed assertionsAttributeError - Missing attributes/methodsImportError/ModuleNotFoundError - Import issuesFixtureNotFoundError - Missing pytest fixturesKey files to check:
pytest.ini, setup.cfg - Configurationconftest.py - Shared fixturesrequirements.txt - DependenciesCommon error patterns:
TypeError - Type-related errorsReferenceError - Undefined variablesTimeout exceeded - Async operation timeoutsCannot find module - Import/require issuesKey files to check:
jest.config.js, vitest.config.js - Test configurationpackage.json - Dependencies and scriptstsconfig.json - TypeScript settingsCommon error patterns:
AssertionFailedError - Failed assertionsNullPointerException - Null reference accessClassNotFoundException - Missing classesComparisonFailure - Value comparison failuresKey files to check:
pom.xml (Maven) or build.gradle (Gradle) - DependenciesCommon error patterns:
Key commands:
go test -v # Verbose output
go test -race # Race detection
go test -cover # Coverage
| Category | Keywords | Common Fix |
|----------|----------|------------|
| Assertion failure | assert, expected, actual | Fix test expectation or implementation |
| Null/undefined | null, undefined, NullPointer | Add null checks or fix data flow |
| Type error | TypeError, type mismatch | Fix types or add type conversion |
| Timeout | timeout, exceeded | Increase timeout or fix slow code |
| Import error | ModuleNotFound, Cannot find | Install dependency or fix import path |
| Mock issue | assert_called, Expected call | Fix mock configuration or code path |
| Async error | Promise, await, async | Properly handle async operations |
| Setup failure | fixture, beforeEach, setUp | Fix test initialization |
references/error_patterns.md - Comprehensive error pattern catalog with detailed examples for each framework and languagereferences/debugging_strategies.md - Advanced debugging techniques, tools, and systematic approaches for complex failuresTake arabelatso/error-explanation-generator from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference npx.
Without those the skill loads but fails at the first command.