error-handling

error-handling

Beliebt

Error handling patterns using wellcrafted trySync and tryAsync. Use when writing error handling code, using try-catch blocks, or working with Result types and graceful error recovery.

3.9KSterne
262Forks
Aktualisiert 1/21/2026
SKILL.md
readonlyread-only
name
error-handling
description

Error handling patterns using wellcrafted trySync and tryAsync. Use when writing error handling code, using try-catch blocks, or working with Result types and graceful error recovery.

Error Handling with wellcrafted trySync and tryAsync

Use trySync/tryAsync Instead of try-catch for Graceful Error Handling

When handling errors that can be gracefully recovered from, use trySync (for synchronous code) or tryAsync (for asynchronous code) from wellcrafted instead of traditional try-catch blocks. This provides better type safety and explicit error handling.

The Pattern

import { trySync, tryAsync, Ok, Err } from 'wellcrafted/result';

// SYNCHRONOUS: Use trySync for sync operations
const { data, error } = trySync({
	try: () => {
		const parsed = JSON.parse(jsonString);
		return validateData(parsed); // Automatically wrapped in Ok()
	},
	catch: (e) => {
		// Gracefully handle parsing/validation errors
		console.log('Using default configuration');
		return Ok(defaultConfig); // Return Ok with fallback
	},
});

// ASYNCHRONOUS: Use tryAsync for async operations
await tryAsync({
	try: async () => {
		const child = new Child(session.pid);
		await child.kill();
		console.log(`Process killed successfully`);
	},
	catch: (e) => {
		// Gracefully handle the error
		console.log(`Process was already terminated`);
		return Ok(undefined); // Return Ok(undefined) for void functions
	},
});

// Both support the same catch patterns
const syncResult = trySync({
	try: () => riskyOperation(),
	catch: (error) => {
		// For recoverable errors, return Ok with fallback value
		return Ok('fallback-value');
		// For unrecoverable errors, return Err
		return ServiceErr({
			message: 'Operation failed',
			cause: error,
		});
	},
});

Key Rules

  1. Choose the right function - Use trySync for synchronous code, tryAsync for asynchronous code
  2. Always await tryAsync - Unlike try-catch, tryAsync returns a Promise and must be awaited
  3. trySync returns immediately - No await needed for synchronous operations
  4. Match return types - If the try block returns T, the catch should return Ok<T> for graceful handling
  5. Use Ok(undefined) for void - When the function returns void, use Ok(undefined) in the catch
  6. Return Err for propagation - Use custom error constructors that return Err when you want to propagate the error
  7. CRITICAL: Wrap destructured errors with Err() - When you destructure { data, error } from tryAsync/trySync, the error variable is the raw error value, NOT wrapped in Err. You must wrap it before returning:
// WRONG - error is just the raw TaggedError, not a Result
const { data, error } = await tryAsync({...});
if (error) return error; // TYPE ERROR: Returns TaggedError, not Result

// CORRECT - wrap with Err() to return a proper Result
const { data, error } = await tryAsync({...});
if (error) return Err(error); // Returns Err<TaggedError>

This is different from returning the entire result object:

// This is also correct - userResult is already a Result type
const userResult = await tryAsync({...});
if (userResult.error) return userResult; // Returns the full Result

Examples

// SYNCHRONOUS: JSON parsing with fallback
const { data: config } = trySync({
	try: () => JSON.parse(configString),
	catch: (e) => {
		console.log('Invalid config, using defaults');
		return Ok({ theme: 'dark', autoSave: true });
	},
});

// SYNCHRONOUS: File system check
const { data: exists } = trySync({
	try: () => fs.existsSync(path),
	catch: () => Ok(false), // Assume doesn't exist if check fails
});

// ASYNCHRONOUS: Graceful process termination
await tryAsync({
	try: async () => {
		await process.kill();
	},
	catch: (e) => {
		console.log('Process already dead, continuing...');
		return Ok(undefined);
	},
});

// ASYNCHRONOUS: File operations with fallback
const { data: content } = await tryAsync({
	try: () => readFile(path),
	catch: (e) => {
		console.log('File not found, using default');
		return Ok('default content');
	},
});

// EITHER: Error propagation (works with both)
const { data, error } = await tryAsync({
	try: () => criticalOperation(),
	catch: (error) =>
		ServiceErr({
			message: 'Critical operation failed',
			cause: error,
		}),
});
if (error) return Err(error);

When to Use trySync vs tryAsync vs try-catch

  • Use trySync when:

    • Working with synchronous operations (JSON parsing, validation, calculations)
    • You need immediate Result types without promises
    • Handling errors in synchronous utility functions
    • Working with filesystem sync operations
  • Use tryAsync when:

    • Working with async/await operations
    • Making network requests or database calls
    • Reading/writing files asynchronously
    • Any operation that returns a Promise
  • Use traditional try-catch when:

    • In module-level initialization code where you can't await
    • For simple fire-and-forget operations
    • When you're outside of a function context
    • When integrating with code that expects thrown exceptions

You Might Also Like

Related Skills

coding-agent

coding-agent

179Kdev-codegen

Run Codex CLI, Claude Code, OpenCode, or Pi Coding Agent via background process for programmatic control.

openclaw avataropenclaw
Holen
add-uint-support

add-uint-support

97Kdev-codegen

Add unsigned integer (uint) type support to PyTorch operators by updating AT_DISPATCH macros. Use when adding support for uint16, uint32, uint64 types to operators, kernels, or when user mentions enabling unsigned types, barebones unsigned types, or uint support.

pytorch avatarpytorch
Holen
at-dispatch-v2

at-dispatch-v2

97Kdev-codegen

Convert PyTorch AT_DISPATCH macros to AT_DISPATCH_V2 format in ATen C++ code. Use when porting AT_DISPATCH_ALL_TYPES_AND*, AT_DISPATCH_FLOATING_TYPES*, or other dispatch macros to the new v2 API. For ATen kernel files, CUDA kernels, and native operator implementations.

pytorch avatarpytorch
Holen
skill-writer

skill-writer

97Kdev-codegen

Guide users through creating Agent Skills for Claude Code. Use when the user wants to create, write, author, or design a new Skill, or needs help with SKILL.md files, frontmatter, or skill structure.

pytorch avatarpytorch
Holen

Implements JavaScript classes in C++ using JavaScriptCore. Use when creating new JS classes with C++ bindings, prototypes, or constructors.

oven-sh avataroven-sh
Holen

Creates JavaScript classes using Bun's Zig bindings generator (.classes.ts). Use when implementing new JS APIs in Zig with JSC integration.

oven-sh avataroven-sh
Holen