Guides error handling for async operations and API calls. Use when junior asks "what if this fails", "handle errors", "try catch", "network error", or builds features with fetch, promises, or external services.
"Errors are not failures — they're information. Handle them like the valuable data they are."
Activate this skill when reviewing:
❌ try {
await submitForm();
} catch (error) {
// TODO: handle later (never happens)
}
✅ try {
await submitForm();
} catch (error) {
console.error('Form submission failed:', error);
setError('Could not submit. Please try again.');
}
❌ function getUser(id) {
try {
return database.query(id);
} catch {
return null; // Caller has no idea it failed
}
}
✅ function getUser(id) {
return database.query(id); // Let caller decide
}
// In UI layer
try {
const user = await getUser(id);
} catch (error) {
showToast('Could not load user');
}
❌ catch (error) {
setError('An error occurred');
}
✅ catch (error) {
if (error.code === 'NETWORK_ERROR') {
setError('Check your internet connection');
} else if (error.code === 'NOT_FOUND') {
setError('User not found');
} else {
setError('Something went wrong. Please try again.');
}
}
❌ res.status(500).json({
error: error.message,
stack: error.stack
});
✅ logger.error('Request failed', { error, requestId });
res.status(500).json({
error: 'Something went wrong'
});
❌ try {
setLoading(true);
await fetchData();
setLoading(false);
} catch (error) {
handleError(error);
// Loading stays true forever!
}
✅ try {
setLoading(true);
await fetchData();
} catch (error) {
handleError(error);
} finally {
setLoading(false); // Always runs
}
Ask the junior these questions instead of giving answers:
TypeError: Cannot read property 'map' of undefinedasync function fetchWithRetry(url: string, retries = 3): Promise<Response> {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response;
} catch (error) {
if (retries > 0) {
await sleep(1000);
return fetchWithRetry(url, retries - 1);
}
throw error;
}
}
function validateForm(data: FormData) {
const errors: Record<string, string> = {};
if (!data.email) {
errors.email = 'Email is required';
} else if (!isValidEmail(data.email)) {
errors.email = 'Please enter a valid email';
}
return {
isValid: Object.keys(errors).length === 0,
errors
};
}
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, info) {
logError(error, info);
}
render() {
if (this.state.hasError) {
return <FallbackUI />;
}
return this.props.children;
}
}
See detailed patterns in:
/standards/global/error-handling.md| Flag | Question to Ask |
|------|-----------------|
| Empty catch block | "What happens when this fails?" |
| catch (e) { return null } | "How will the caller know it failed?" |
| No loading state | "What does the user see while waiting?" |
| Technical error shown | "Will the user understand this message?" |
| No finally for cleanup | "Is loading state stuck on error?" |
| console.log instead of error | "How will you find this in production logs?" |
npx skills add DanielPodolsky/error-handling-fundamentals下载完整 Skill 目录,包含 SKILL.md 及所有相关文件
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer