Error prevention and best practices enforcement for agent-assisted coding. Use when writing code to catch common mistakes, enforce patterns, prevent bugs, validate inputs, handle errors, follow coding standards, avoid anti-patterns, and ensure code quality through proactive checks and guardrails.
This skill helps agents write higher-quality code by proactively preventing common errors, enforcing best practices, and applying defensive programming patterns. Use this skill when writing any code to reduce bugs, improve maintainability, and follow established patterns.
For best results with this skill:
**Minimum Requirements:**
**Why This Matters:**
Error prevention requires deep reasoning about edge cases, type safety, and failure modes. Stronger models with extended thinking capabilities will:
**Optimal Setup (February 2026):**
**Suboptimal (will miss issues):**
If your agent doesn't support model selection, this skill will still help, but expect fewer proactive warnings about subtle bugs.
Activate this skill when:
**Always validate inputs at function boundaries:**
```typescript
// ❌ BAD: No validation
function processUser(id: string) {
return database.query(id); // What if id is empty? SQL injection?
}
// ✅ GOOD: Guard at entry
function processUser(id: string) {
if (!id || typeof id !== 'string') {
throw new Error('Invalid user ID: must be non-empty string');
}
if (!/^[a-zA-Z0-9-]+$/.test(id)) {
throw new Error('Invalid user ID format: alphanumeric and hyphens only');
}
return database.query(id);
}
```
**Validation checklist:**
**Never silently swallow errors:**
```typescript
// ❌ BAD: Silent failure
try {
await criticalOperation();
} catch (e) {
// Silent failure - bug goes unnoticed
}
// ✅ GOOD: Explicit handling
try {
await criticalOperation();
} catch (e) {
logger.error('Critical operation failed', { error: e, context });
throw new ApplicationError('Operation failed', { cause: e });
}
```
**Error handling checklist:**
**Treat null/undefined as exceptional:**
```typescript
// ❌ BAD: Assumes data exists
function getUserName(user) {
return user.profile.name; // Can crash on null user or profile
}
// ✅ GOOD: Defensive checks
function getUserName(user: User | null): string {
if (!user?.profile?.name) {
return 'Unknown User'; // Safe default or throw error
}
return user.profile.name;
}
```
**Null safety checklist:**
**Handle async errors and edge cases:**
```typescript
// ❌ BAD: Unhandled promise rejection
async function loadData() {
const data = await fetch(url); // What if network fails?
return data;
}
// ✅ GOOD: Comprehensive async handling
async function loadData(): Promise<Result<Data>> {
try {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);
const response = await fetch(url, { signal: controller.signal });
clearTimeout(timeout);
if (!response.ok) {
return { error: `HTTP ${response.status}` };
}
const data = await response.json();
return { data };
} catch (e) {
if (e.name === 'AbortError') {
return { error: 'Request timeout' };
}
return { error: `Network error: ${e.message}` };
}
}
```
**Async safety checklist:**
**Use TypeScript to prevent bugs at compile time:**
```typescript
// ❌ BAD: Stringly-typed
type Status = string; // Can be anything
function setStatus(status: Status) { ... }
setStatus("complted"); // Typo not caught
// ✅ GOOD: Union types
type Status = 'pending' | 'completed' | 'failed';
function setStatus(status: Status) { ... }
setStatus("complted"); // Compile error!
// ✅ BETTER: Discriminated unions for state machines
type State =
| { status: 'idle' }
| { status: 'loading'; startedAt: number }
| { status: 'success'; data: Data }
| { status: 'error'; error: Error };
```
**Type safety checklist:**
**Always validate indices and ranges:**
```typescript
// ❌ BAD: No bounds checking
function getItem(index: number) {
return items[index]; // Returns undefined if out of bounds
}
// ✅ GOOD: Explicit bounds checking
function getItem(index: number): Item {
if (index < 0 || index >= items.length) {
throw new RangeError(`Index ${index} out of bounds [0, ${items.length})`);
}
return items[index];
}
```
**Boundary checklist:**
**Always release resources:**
```typescript
// ❌ BAD: Resource leak
async function processFile(path: string) {
const file = await fs.open(path);
const data = await file.read();
return data; // File never closed!
}
// ✅ GOOD: Guaranteed cleanup
async function processFile(path: string) {
const file = await fs.open(path);
try {
const data = await file.read();
return data;
} finally {
await file.close(); // Always executed
}
}
// ✅ BETTER: Using resource patterns
await using file = await fs.open(path); // Auto-closes
const data = await file.read();
return data;
```
**Resource checklist:**
**Prefer immutable operations:**
```typescript
// ❌ BAD: Mutates input
function addItem(list: Item[], item: Item) {
list.push(item); // Mutates caller's array
return list;
}
// ✅ GOOD: Immutable update
function addItem(list: Item[], item: Item): Item[] {
return [...list, item]; // New array
}
// ✅ GOOD: Immutable object update
function updateUser(user: User, name: string): User {
return { ...user, name }; // New object
}
```
**Immutability checklist:**
**Validate configuration early:**
```typescript
// ❌ BAD: Lazy validation
function sendEmail(to: string) {
const apiKey = process.env.SENDGRID_API_KEY; // Might be undefined
return sendgrid.send({ to, apiKey });
}
// ✅ GOOD: Validate at startup
const config = {
sendgridApiKey: requireEnv('SENDGRID_API_KEY'),
databaseUrl: requireEnv('DATABASE_URL'),
};
function requireEnv(key: string): string {
const value = process.env[key];
if (!value) {
throw new Error(`Missing required env var: ${key}`);
}
return value;
}
```
**Configuration checklist:**
**Code as if everything can fail:**
```typescript
// ❌ BAD: Optimistic
function parseJSON(text: string) {
return JSON.parse(text); // Can throw
}
// ✅ GOOD: Defensive
function parseJSON(text: string): Result<any> {
try {
if (!text || text.trim() === '') {
return { error: 'Empty JSON string' };
}
const data = JSON.parse(text);
return { data };
} catch (e) {
return { error: `Invalid JSON: ${e.message}` };
}
}
```
**Defensive checklist:**
```typescript
// ❌ NEVER DO THIS
try {
await importantOperation();
} catch (e) {
// Empty catch - hides bugs
}
```
**Fix:** Always log, re-throw, or return error.
```typescript
// ❌ BAD: Loses stack trace
throw "Something went wrong";
// ✅ GOOD: Proper Error object
throw new Error("Something went wrong");
```
```typescript
// ❌ BAD: Fire and forget
async function handler() {
someAsyncOperation(); // Unhandled rejection risk
}
// ✅ GOOD: Explicit handling
async function handler() {
void someAsyncOperation().catch(logError); // Intentional fire-and-forget
// OR
await someAsyncOperation(); // Wait for completion
}
```
```typescript
// ❌ BAD: Assumes shape without validation
const user = apiResponse as User; // Might not be User!
// ✅ GOOD: Runtime validation
const user = UserSchema.parse(apiResponse); // Throws if invalid
```
```typescript
// ❌ BAD: Unclear meaning
if (status === 2) { ... }
// ✅ GOOD: Named constant
const STATUS_COMPLETED = 2;
if (status === STATUS_COMPLETED) { ... }
// ✅ BETTER: Enum
enum Status { Pending = 1, Completed = 2 }
if (status === Status.Completed) { ... }
```
```typescript
describe('processPayment', () => {
// Test failure modes first
it('throws on invalid amount', () => {
expect(() => processPayment(-10)).toThrow('Invalid amount');
});
it('throws on missing payment method', () => {
expect(() => processPayment(10, null)).toThrow('Payment method required');
});
// Then test happy path
it('processes valid payment', () => {
const result = processPayment(10, { type: 'card' });
expect(result.success).toBe(true);
});
});
```
```typescript
// Test invariants across many inputs
test('parseAmount never returns negative', () => {
fc.assert(fc.property(fc.string(), (input) => {
const result = parseAmount(input);
return result === null || result >= 0;
}));
});
```
Before completing your task, verify:
| Scenario | Pattern |
|----------|---------|
| External API call | Try/catch + timeout + retry logic |
| User input | Validate with schema (Zod, Joi) |
| Array access | Check length before index |
| Object property | Use optional chaining `?.` |
| Async operation | Always await or .catch() |
| Configuration | Validate at startup |
| Type unknown | Use `unknown` + type guards |
| Resource (file/socket) | Use finally or `using` |
| State machine | Discriminated unions |
| Error context | Include error cause chain |
For detailed examples and reference implementations, see:
Leave a review
No reviews yet. Be the first to review this skill!