Error Recovery Skill logo

Error Recovery Skill

Community
zeenie-ai
error-recovery-skill

Handle errors gracefully with retry strategies and fallback patterns

Overview

Publisherzeenie-ai
RepositoryOpenCompany
Skill nameerror-recovery-skill
Stars
912
Forks
137
Bundled files
Instructions only
LicenseMIT
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by zeenie-ai on GitHub. Read the source before you install it.

Installation

Install the Error Recovery Skill AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/zeenie-ai/OpenCompany.git /tmp/OpenCompany
mkdir -p .claude/skills
cp -r /tmp/OpenCompany/server/skills/autonomous/error-recovery-skill .claude/skills/error-recovery-skill
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Error Recovery Skill in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Error Recovery Skill on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Error Recovery Skill is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Error Recovery Pattern

You are an agent that handles errors gracefully through retry strategies, alternative approaches, and graceful degradation.

Error Classification

┌─────────────────────────────────────────────────────────────┐
│                    ERROR CATEGORIES                          │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  TRANSIENT (Retry)          RECOVERABLE (Alternative)       │
│  ─────────────────          ────────────────────────        │
│  • Network timeout          • Missing data → try another    │
│  • Rate limit (429)         • Format error → parse differ   │
│  • Service busy (503)       • Partial failure → use partial │
│  • Connection reset         • Auth expired → re-auth        │
│                                                              │
│  PERMANENT (Report)         CRITICAL (Escalate)             │
│  ──────────────────         ───────────────────             │
│  • Not found (404)          • Security violation            │
│  • Permission denied (403)  • Data corruption               │
│  • Invalid input (400)      • System failure                │
│  • Resource deleted (410)   • Unrecoverable state           │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Retry Strategy

For transient errors, use exponential backoff:

┌─────────────────────────────────────────────────────────────┐
│                 EXPONENTIAL BACKOFF                          │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│   Attempt 1 ──▶ FAIL ──▶ Wait 1 second                      │
│                              │                               │
│                              ▼                               │
│   Attempt 2 ──▶ FAIL ──▶ Wait 2 seconds                     │
│                              │                               │
│                              ▼                               │
│   Attempt 3 ──▶ FAIL ──▶ Wait 4 seconds                     │
│                              │                               │
│                              ▼                               │
│   Attempt 4 ──▶ FAIL ──▶ Report failure                     │
│                                                              │
│   Formula: wait_time = 2^(attempt - 1) seconds              │
│   Max attempts: 4 (configurable)                            │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Code Mode Retry Implementation

python
import json
import time

def with_retry(operation, max_attempts=4):
    """Execute operation with exponential backoff retry."""
    last_error = None

    for attempt in range(1, max_attempts + 1):
        try:
            result = operation()
            return {"success": True, "result": result, "attempts": attempt}
        except Exception as e:
            last_error = str(e)

            # Check if error is retryable
            if is_permanent_error(e):
                return {
                    "success": False,
                    "error": last_error,
                    "error_type": "permanent",
                    "attempts": attempt
                }

            # Wait before retry (exponential backoff)
            if attempt < max_attempts:
                wait_time = 2 ** (attempt - 1)
                time.sleep(wait_time)

    return {
        "success": False,
        "error": last_error,
        "error_type": "transient_exhausted",
        "attempts": max_attempts
    }

def is_permanent_error(e):
    """Check if error is permanent (should not retry)."""
    error_msg = str(e).lower()
    permanent_indicators = [
        "not found", "404",
        "permission denied", "403", "forbidden",
        "invalid", "400", "bad request",
        "unauthorized", "401"
    ]
    return any(indicator in error_msg for indicator in permanent_indicators)

# Usage
result = with_retry(lambda: risky_operation())
print(json.dumps(result, indent=2))

Alternative Approach Pattern

When the primary approach fails, try alternatives:

┌─────────────────────────────────────────────────────────────┐
│                 ALTERNATIVE APPROACHES                       │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│   Primary: API call to service A                            │
│       │                                                     │
│       ▼                                                     │
│   FAILED (service down)                                     │
│       │                                                     │
│       ▼                                                     │
│   Alternative 1: Try service B (backup API)                 │
│       │                                                     │
│       ▼                                                     │
│   FAILED (rate limited)                                     │
│       │                                                     │
│       ▼                                                     │
│   Alternative 2: Use cached data                            │
│       │                                                     │
│       ▼                                                     │
│   SUCCESS (stale but available)                             │
│       │                                                     │
│       ▼                                                     │
│   Return with warning: "Data may be outdated"               │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Self-Delegation for Retry

Use delegation to retry with a different approach:

json
{
  "task": "Retry: Get weather data using alternative source",
  "context": "Attempt: 2/3
Error: Primary weather API timeout
Previous approach: OpenWeatherMap API
New approach: Try WeatherAPI.com or use cached forecast
Original request: Weather for New York"
}

Graceful Degradation

When full success isn't possible, return partial results:

┌─────────────────────────────────────────────────────────────┐
│                 GRACEFUL DEGRADATION                         │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│   Request: "Get user profile with posts and followers"      │
│                                                              │
│   ┌─────────────┐  ┌─────────────┐  ┌─────────────┐        │
│   │   Profile   │  │    Posts    │  │  Followers  │        │
│   │   SUCCESS   │  │   FAILED    │  │   SUCCESS   │        │
│   └─────────────┘  └─────────────┘  └─────────────┘        │
│                                                              │
│   Response:                                                  │
│   {                                                          │
│     "profile": { ... },      // Full data                   │
│     "posts": null,           // Unavailable                 │
│     "posts_error": "Service temporarily unavailable",       │
│     "followers": [ ... ],    // Full data                   │
│     "partial": true,         // Indicates degraded response │
│     "degraded_fields": ["posts"]                            │
│   }                                                          │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Code Mode Graceful Degradation

python
import json

def fetch_user_data(user_id):
    """Fetch user data with graceful degradation."""
    result = {
        "user_id": user_id,
        "partial": False,
        "errors": []
    }

    # Try to get profile (required)
    try:
        result["profile"] = get_profile(user_id)
    except Exception as e:
        # Profile is required - cannot degrade
        return {
            "success": False,
            "error": f"Cannot fetch required profile: {e}"
        }

    # Try to get posts (optional, can degrade)
    try:
        result["posts"] = get_posts(user_id)
    except Exception as e:
        result["posts"] = None
        result["errors"].append(f"posts: {e}")
        result["partial"] = True

    # Try to get followers (optional, can degrade)
    try:
        result["followers"] = get_followers(user_id)
    except Exception as e:
        result["followers"] = None
        result["errors"].append(f"followers: {e}")
        result["partial"] = True

    return {"success": True, "data": result}

# Simulated functions
def get_profile(uid): return {"name": "John", "email": "john@example.com"}
def get_posts(uid): raise Exception("Service unavailable")
def get_followers(uid): return [{"id": 1, "name": "Jane"}]

output = fetch_user_data("user_123")
print(json.dumps(output, indent=2))

Error Recovery in Agentic Loops

When an iteration fails in an agentic loop:

┌─────────────────────────────────────────────────────────────┐
│              LOOP ERROR RECOVERY                             │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│   Iteration 2: FAILED                                       │
│       │                                                     │
│       ▼                                                     │
│   Classify Error                                            │
│       │                                                     │
│       ├──▶ Transient? ──▶ Retry same iteration             │
│       │                                                     │
│       ├──▶ Recoverable? ──▶ Try alternative approach       │
│       │                                                     │
│       └──▶ Permanent? ──▶ Skip or report                   │
│                                                              │
│   Continue to Iteration 3 with updated context:            │
│   "Iteration 2 failed: [reason]. Proceeding with           │
│    partial results from Iteration 1."                       │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Delegation with Error Context

json
{
  "task": "Continue: Process remaining items (skip failed)",
  "context": "Iteration: 3/5
Progress: Processed items 1-5, item 3 failed (invalid format)
State: Results for items [1,2,4,5] available
Error handling: Skipping item 3, continuing with remaining
Next: Process items 6-10"
}

Error Reporting Best Practices

What to Include

┌─────────────────────────────────────────────────────────────┐
│                 ERROR REPORT STRUCTURE                       │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│   1. WHAT failed                                            │
│      "Failed to send WhatsApp message"                      │
│                                                              │
│   2. WHY it failed                                          │
│      "Recipient phone number not registered on WhatsApp"    │
│                                                              │
│   3. WHAT was tried                                         │
│      "Attempted 3 times with exponential backoff"           │
│                                                              │
│   4. WHAT can be done                                       │
│      "Try a different contact method (SMS, email) or        │
│       verify the phone number is correct"                   │
│                                                              │
│   5. PARTIAL results (if any)                               │
│      "Message was prepared but not delivered"               │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Example Error Response

json
{
  "success": false,
  "error": {
    "type": "delivery_failed",
    "message": "Failed to send WhatsApp message",
    "reason": "Recipient not on WhatsApp",
    "attempts": 3,
    "recovery_attempted": true,
    "partial_result": {
      "message_prepared": true,
      "recipient_validated": false
    }
  },
  "suggestions": [
    "Verify the phone number format (+1234567890)",
    "Try sending via SMS instead",
    "Check if recipient has WhatsApp installed"
  ]
}

Anti-Patterns to Avoid

1. Silent Failures

// Never do this
try:
    result = risky_operation()
except:
    pass  // Error swallowed silently

// Always report
try:
    result = risky_operation()
except Exception as e:
    return {"success": False, "error": str(e)}

2. Infinite Retry

// Never do this
while True:
    try:
        result = operation()
        break
    except:
        continue  // Infinite loop

// Always limit attempts
for attempt in range(MAX_ATTEMPTS):
    ...

3. Retry Permanent Errors

// Never retry these
- 404 Not Found
- 403 Forbidden
- 401 Unauthorized
- 400 Bad Request

// Only retry these
- 429 Too Many Requests
- 503 Service Unavailable
- 504 Gateway Timeout
- Connection errors

4. Lose Context on Error

// Never do this
except Exception:
    return "An error occurred"

// Preserve context
except Exception as e:
    return f"Failed at step {step}: {e}. Progress: {progress}"

Frequently asked questions

What does the Error Recovery Skill AI skill do?

Handle errors gracefully with retry strategies and fallback patterns

Why use Error Recovery Skill on TypingMind?

Because you install it once and use it with any model. Error Recovery Skill is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Error Recovery Skill in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/zeenie-ai/OpenCompany/tree/main/server/skills/autonomous/error-recovery-skill. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Error Recovery Skill?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Error Recovery Skill?

As many as you like. As long as a model supports skills, you can use Error Recovery Skill with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Error Recovery Skill AI skill free?

Yes. It is published on GitHub by zeenie-ai under the MIT license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇