plugins/midnight-dapp/skills/error-handling/SKILL.md
Use when implementing error handling in Midnight DApps, displaying errors to users, handling proof generation failures, managing transaction rejections, or dealing with network disconnections.
npx skillsauth add aaronbassett/midnight-knowledgebase midnight-dapp:error-handlingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
4 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Handle errors gracefully in Midnight DApps with user-friendly messaging, proper error classification, and recovery strategies.
Midnight DApps encounter several categories of errors:
| Category | Source | Examples | |----------|--------|----------| | Proof Errors | ZK proof generation | Timeout, constraint violations, witness failures | | Transaction Errors | Contract execution | Insufficient balance, state conflicts, rejections | | Network Errors | Infrastructure | Indexer down, proof server unavailable, WebSocket disconnect | | Wallet Errors | User interaction | Not installed, rejected, wrong network |
Technical errors should be translated to actionable messages:
// Technical error
"Circuit constraint failed at gate 1042: input > max_value"
// User-friendly message
"The amount exceeds the maximum allowed. Please enter a smaller value."
Different errors require different recovery strategies:
| Document | Description | |----------|-------------| | proof-errors.md | ZK proof failures and diagnosis | | transaction-errors.md | Contract execution errors | | network-errors.md | Connection and timeout handling | | user-messaging.md | UX guidelines for error display |
| Example | Description | |---------|-------------| | error-boundary/ | React error boundary for Midnight | | error-toast/ | Toast notification component | | typed-errors/ | Custom error classes and catalog |
import { MidnightError, ErrorCode } from './MidnightErrors';
// Throw typed errors in your code
throw new MidnightError(
ErrorCode.PROOF_TIMEOUT,
'Proof generation timed out',
{ timeoutMs: 60000, operation: 'transfer' }
);
import { classifyError } from './errorUtils';
try {
await contract.callTx.transfer(recipient, amount, witnesses);
} catch (error) {
const classified = classifyError(error);
// { code, message, userMessage, suggestion, retryable, category }
}
import { useErrorToast } from './useErrorToast';
function TransferButton() {
const { showError } = useErrorToast();
const handleTransfer = async () => {
try {
await performTransfer();
} catch (error) {
showError(error); // Shows user-friendly toast
}
};
}
import { MidnightErrorBoundary } from './MidnightErrorBoundary';
function App() {
return (
<MidnightErrorBoundary
onReset={() => window.location.reload()}
fallback={<ErrorPage />}
>
<MyDApp />
</MidnightErrorBoundary>
);
}
interface ClassifiedError {
code: string;
message: string;
userMessage: string;
suggestion: string;
retryable: boolean;
category: 'proof' | 'transaction' | 'network' | 'wallet' | 'unknown';
}
function classifyError(error: unknown): ClassifiedError {
if (error instanceof MidnightError) {
return {
code: error.code,
message: error.message,
userMessage: ERROR_CATALOG[error.code].userMessage,
suggestion: ERROR_CATALOG[error.code].suggestion,
retryable: ERROR_CATALOG[error.code].retryable,
category: ERROR_CATALOG[error.code].category,
};
}
// Classify by error message patterns
const message = error instanceof Error ? error.message : String(error);
return classifyByMessage(message);
}
async function withRetry<T>(
operation: () => Promise<T>,
options: {
maxRetries: number;
baseDelayMs: number;
shouldRetry: (error: unknown) => boolean;
}
): Promise<T> {
let lastError: unknown;
for (let attempt = 1; attempt <= options.maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
lastError = error;
if (!options.shouldRetry(error) || attempt === options.maxRetries) {
throw error;
}
const delay = options.baseDelayMs * Math.pow(2, attempt - 1);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw lastError;
}
const ErrorContext = createContext<ErrorContextValue | null>(null);
function ErrorProvider({ children }: { children: ReactNode }) {
const [errors, setErrors] = useState<ClassifiedError[]>([]);
const addError = useCallback((error: unknown) => {
const classified = classifyError(error);
setErrors(prev => [...prev, classified]);
// Auto-dismiss non-critical errors
if (classified.category !== 'wallet') {
setTimeout(() => dismissError(classified.code), 5000);
}
}, []);
const dismissError = useCallback((code: string) => {
setErrors(prev => prev.filter(e => e.code !== code));
}, []);
return (
<ErrorContext.Provider value={{ errors, addError, dismissError }}>
{children}
</ErrorContext.Provider>
);
}
wallet-integration - Wallet-specific error handlingproof-handling - Proof generation error patternstransaction-flows - Transaction error recoverystate-management - State read error handling/dapp-check - Validates error handling patterns/dapp-debug errors - Diagnose error handling issuestools
Use when setting up Midnight development environment, installing Compact compiler and developer tools, configuring proof server, verifying prerequisites, or getting started with Midnight development.
tools
--- name: midnight-tooling:midnight-debugging description: Use when encountering Midnight errors like "compact: command not found", "ERR_UNSUPPORTED_DIR_IMPORT", version mismatches, proof server failures, "@midnight-ntwrk" package errors, or compilation failures. --- # Midnight Environment Debugging Expert knowledge for identifying and resolving common Midnight development toolchain issues. ## Diagnostic Approach When encountering Midnight-related errors, follow this systematic approach: 1.
tools
Use when checking Midnight version compatibility, understanding pragma language_version, verifying compiler and runtime version relationships, or troubleshooting version mismatch errors between Midnight components.
tools
Use when setting up CI/CD for Midnight projects, configuring GitHub Actions for Compact contract compilation, running TypeScript tests in CI, validating version consistency, or automating contract builds.