Custom error classes and error handling
Scanned 9/6/2026
Install to Claude Code
npx -y skills add testdriverai/testdriverai --skill testdriver-errors --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Testdriver Errors?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/testdriverai-testdriver-errors)More formats (shields.io, HTML) on the badges page.
---
name: testdriver:errors
description: Custom error classes and error handling
---
<!-- Generated from errors.mdx. DO NOT EDIT. -->
## Overview
TestDriver provides custom error classes with rich debugging information. These are exported from the SDK and can be used for `instanceof` checks in your tests.
```javascript
import TestDriver, { ElementNotFoundError, AIError } from 'testdriverai';
```
## ElementNotFoundError
Thrown when `find()` cannot locate an element on screen, or when calling `click()`/`hover()` on an unfound element.
```javascript
try {
await testdriver.find('nonexistent button').click();
} catch (error) {
if (error instanceof ElementNotFoundError) {
console.log(error.description); // "nonexistent button"
console.log(error.screenshotPath); // path to debug screenshot
console.log(error.pixelDiffPath); // path to pixel diff image
}
}
```
### Properties
<ParamField path="name" type="string">
Always `"ElementNotFoundError"`.
</ParamField>
<ParamField path="message" type="string">
Enhanced message with a debug block containing element description, cache status, similarity scores, and AI response details.
</ParamField>
<ParamField path="description" type="string">
The original element description passed to `find()`.
</ParamField>
<ParamField path="screenshotPath" type="string | null">
Absolute path to a debug screenshot saved at the time of failure. Written to `<os.tmpdir>/testdriver-debug/screenshot-<timestamp>.png`.
</ParamField>
<ParamField path="pixelDiffPath" type="string | null">
Absolute path to a pixel diff image showing the comparison between the cached and current screenshots. Written to `<os.tmpdir>/testdriver-debug/pixel-diff-error-<timestamp>.png`. Only present when cache was involved.
</ParamField>
<ParamField path="cachedImagePath" type="string | null">
URL to the cached image that was compared against.
</ParamField>
<ParamField path="aiResponse" type="object | null">
Sanitized AI response object. Large binary fields (`croppedImage`, `screenshot`, `pixelDiffImage`) are removed. Contains cache metadata like `similarity`, `cacheHit`, `cacheStrategy`, `cacheDiffPercent`, and `threshold`.
</ParamField>
<ParamField path="timestamp" type="string">
ISO 8601 timestamp of when the error was created.
</ParamField>
### Enhanced Message
The error message is automatically enhanced with debugging information:
```
Element not found: "submit button"
=== Element Debug Info ===
Element: submit button
Cache Hit: false
Similarity: 0.23
Cache Strategy: pixel-diff
Threshold: 0.05
AI Response Element: null
```
### Stack Trace Cleaning
Stack traces are automatically cleaned to remove internal SDK frames (`Element.*`, `sdk.js` internals), showing only your test code for easier debugging.
## AIError
Thrown when `act()` exhausts all retry attempts.
```javascript
try {
await testdriver.act('perform complex workflow', { tries: 3 });
} catch (error) {
if (error instanceof AIError) {
console.log(error.task); // "perform complex workflow"
console.log(error.tries); // 3
console.log(error.duration); // 15234 (ms)
console.log(error.cause); // underlying Error
}
}
```
### Properties
<ParamField path="name" type="string">
Always `"AIError"`.
</ParamField>
<ParamField path="message" type="string">
Enhanced message with execution details block.
</ParamField>
<ParamField path="task" type="string">
The task description passed to `act()`.
</ParamField>
<ParamField path="tries" type="number">
Number of attempts that were made.
</ParamField>
<ParamField path="maxTries" type="number">
Maximum number of attempts configured.
</ParamField>
<ParamField path="duration" type="number">
Total execution time in milliseconds.
</ParamField>
<ParamField path="cause" type="Error | undefined">
The underlying error that caused the final failure.
</ParamField>
<ParamField path="timestamp" type="string">
ISO 8601 timestamp of when the error was created.
</ParamField>
### Enhanced Message
```
AI failed: Element not found after 3 attempts
=== AI Execution Details ===
Task: perform complex workflow
Tries: 3 / 3
Duration: 15234ms
Cause: ElementNotFoundError: Element not found: "submit button"
```
## Internal Error Classes
These errors are used internally by the agent and are not exported, but may appear as the `cause` of an `AIError`:
### MatchError
Thrown when element matching fails (text, image, or assertion).
| Property | Type | Description |
|---|---|---|
| `fatal` | `boolean` | If `true`, cannot be healed. Default: `false` |
| `attachScreenshot` | `boolean` | Always `true` — a screenshot is attached to the error |
### CommandError
Thrown for invalid arguments or unsupported operations.
| Property | Type | Description |
|---|---|---|
| `fatal` | `boolean` | Always `true` |
| `attachScreenshot` | `boolean` | Always `false` |
## Soft Assert Mode
Inside `act()`, assertions run in **soft assert mode**. When an assertion fails, it returns the failure result instead of throwing, allowing the AI to process the failure and adjust its approach.
```javascript
// Inside act(), assertion failures don't throw
await testdriver.act('verify the dashboard shows correct data', {
tries: 3,
});
// The AI can see assertion results and self-correct
```
This is automatic — you don't need to configure it. Regular `assert()` calls outside of `act()` will throw normally on failure.
## Error Handling Patterns
### Catching Specific Errors
```javascript
import TestDriver, { ElementNotFoundError, AIError } from 'testdriverai';
try {
await testdriver.find('submit button').click();
} catch (error) {
if (error instanceof ElementNotFoundError) {
// Element wasn't found — check screenshot for debugging
console.log('Debug screenshot:', error.screenshotPath);
} else if (error instanceof AIError) {
// AI exhausted retries
console.log(`Failed after ${error.tries} tries in ${error.duration}ms`);
} else {
throw error; // Unexpected error
}
}
```
### Using Debug Screenshots
```javascript
try {
const el = await testdriver.find('checkout button');
await el.click();
} catch (error) {
if (error instanceof ElementNotFoundError) {
// Screenshot of what the screen looked like
console.log('Screen:', error.screenshotPath);
// Pixel diff showing cache comparison
console.log('Diff:', error.pixelDiffPath);
// Full AI response metadata
console.log('AI:', JSON.stringify(error.aiResponse, null, 2));
}
}
```
## Types
```typescript
class ElementNotFoundError extends Error {
name: 'ElementNotFoundError';
description: string;
screenshotPath: string | null;
pixelDiffPath: string | null;
cachedImagePath: string | null;
aiResponse: Record<string, any> | null;
timestamp: string;
}
class AIError extends Error {
name: 'AIError';
task: string;
tries: number;
maxTries: number;
duration: number;
cause?: Error;
timestamp: string;
}
```
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!