# Skill: Enforce loud, traceable error handling in generated code > Apply this skill when generating or reviewing any code that touches network requests, databases, email, file I/O, or user input -- so failures surface immediately instead of being swallowed silently. Source: sodigi·learn -- vibecoding/oshibki-ne-padayut-molcha · https://sodigi.io/learn/vibecoding/oshibki-ne-padayut-molcha ## When to use - Writing any function that can fail (HTTP calls, DB queries, file operations, third-party APIs, form submissions). - Reviewing existing code before deploy -- hunt for empty catch blocks and misleading success messages. - The user reports "something broke but I have no idea where" -- the root cause is almost always silent errors. - Setting up a new project or module and establishing error-handling conventions from the start. ## Core rules - Never leave an empty catch/except block. Every error must be handled, rethrown, or logged. No exceptions. - Produce two messages per error: a short polite message for the user ("something went wrong, try again later") and a full technical log entry (what broke, where, with what data). - Do not show a success message until the action has actually completed. "Sent!" appears only after the send succeeded. - Use typed/named errors with codes (NotFound, Unauthorized, ValidationError, RateLimited, InternalError) -- never bare strings like "something broke". - Retry only errors that could resolve by themselves (network timeout, temporary server overload). Do not retry input errors or 404s. - Retries must use exponential backoff with a hard cap (3 attempts max) to avoid hammering downstream services. - Secrets and passwords must never appear in logs. Scrub sensitive fields before logging. ## Procedure 1. Identify every code path that can throw: HTTP calls, DB operations, file reads/writes, email sends, payment calls, user input parsing. 2. For each path, write a typed error class or use the project's error taxonomy (NotFound, Unauthorized, etc.). 3. In each catch block: log the full technical detail (error type, message, stack, request context) to the server log. 4. Return or display a sanitized, human-friendly message to the UI layer -- no stack traces on screen. 5. Guard success indicators: only set "done / sent / saved" state after the async operation resolves successfully. 6. For transient failures (timeout, 503), wrap the call in a retry helper with exponential backoff, max 3 attempts. 7. After writing, enumerate every catch block to the user and confirm none are empty. ## Ready-to-use prompt ``` Whenever you write any code that could break (network requests, database work, sending emails, user input), follow these rules: 1. Never leave an empty error-handling block. Every such block must either handle the failure properly, pass it along, or write it to a log. 2. For every error, produce two messages. For the user -- short and polite, with no technical details. For the log -- full information: what broke, where, and with what data. 3. Do not show the user success until the action has actually completed. If the email did not send, say honestly that it failed and offer to retry. 4. Use clear typed errors with codes: not found, no access, invalid input, too many requests, internal error. 5. Retry a request automatically only if it could have failed by chance (network, timeout). Use exponential backoff and cap attempts at 3. Do not retry input or access errors. At the end, show me a list of the places where the code could fail and how you handle the error in each one. ``` ## Pitfalls - Empty catch blocks: the single most dangerous habit. The error disappears; the problem festers unseen. - Showing the user a success message before confirming success (e.g., "Your message was sent!" before the email API responded). - Logging full request objects that contain passwords, tokens, or API keys -- always scrub sensitive fields first. - Retrying non-retriable errors (wrong password, 404) in a tight loop -- wastes resources and can overwhelm downstream services. - Returning bare string errors like "error occurred" instead of typed codes -- makes it impossible to handle errors programmatically. - Catching all errors with a single broad handler that silently swallows subtypes -- use specific catches.