- name
- error-recovery-strategy
- description
- Classify error into 4 buckets (transient / deterministic / stale / unknown) and pick one of 5 actions (retry / switch / fallback / refresh-then-retry / ask-user / skip).
USE WHEN: tool returns non-success, sub-agent `status: closed-failed`, exception escapes, timeout fires, weird partial-success result, ECONNREFUSED / 5xx / 429 / timeout / permission denied / "command not found" / "fail" / "error" / "出错了" / "挂" / "失败".
TRIGGER PHRASES: "出错了", "failed", "挂", "error", "失败", "fail", "permission denied", "command not found", "ECONNREFUSED", "timeout", "挂了", "再试一次", "retry", "这不行", "没用", "fallback", "退路", "不行", "跑不通", "broken".
SKIP WHEN: operation succeeded, error is in user input (clarification case), error is part of expected flow (grep 0 matches).
- license
- Apache-2.0
- compatibility
- Requires MiniMax Code with Agent Plugins 1.0 support.
- metadata
- {"author":"antianqi","version":"0.1.2","inspired-by":"https://github.com/openai/codex/blob/main/codex-rs/code-mode/src/grpc_session/reconnect.rs and core/src/session/multi_agents.rs","changes-from-v0.1.1":"Audit gap: the sub-agent invocation example in '## Example' (line 115) used the Codex-style `task(subagent=...)` shape; switched to the canonical mcode 0.2.4 `task(agent_name=..., prompt=...)` shape (mcode accepts `subagent_type=` as a runtime alias but `agent_name=` is the canonical form per `cli.js:B6c`). The round-1 72952c9 amend touched 4 Skills (fork-context-decision / delegate-with-context / parallel-fanout / model-router) and missed this 5th; the v1.0.4 round-2 close-out also missed it. Caught by the v1.0.4 audit sweep across all 23 Skills' code blocks. The rest of the Skill body is unchanged."}
# Error Recovery Strategy
When something fails, the default human reaction is "retry." That is often the **wrong**
default. Retrying a permission-denied file write burns the same error three times in a row.
Retrying a network timeout that won't resolve in 30 seconds burns three minutes.
This Skill codifies the decision: **categorize the error first, then pick one of five
recovery actions, then commit to it explicitly.**
## When to use
Activate when **any** of these is true:
- A tool call returns a non-success result (non-zero exit, HTTP 4xx/5xx, exception,
error message).
- A sub-agent reports `status: closed-failed` in the family file.
- An exception escapes from any of your own code or a library you called.
- A timeout fires on a long-running operation.
- A "weird" result comes back that might be a partial success (e.g. command exited 0
but produced no output where you expected output).
## When NOT to use
- The operation succeeded. Do not second-guess success.
- The error is in user input (bad prompt, missing file the user should provide). That is
not a recovery case; it is a clarification case.
- The error is part of expected flow (e.g. a `grep` returning 0 matches is an exit-1, but
it is not a failure for the search use case).
## Process
1. **Stop. Do not retry yet.** Even if the obvious answer is "retry," run this Skill.
2. **Categorize the error** into one of four buckets:
| Bucket | Signals | Examples |
|---|---|---|
| **transient** | Will probably succeed if tried again soon | Network timeout, HTTP 429/503, "ECONNRESET", "temporarily unavailable", rate limit |
| **deterministic** | Will fail every time the same way | Permission denied, file not found, "command not found", invalid syntax, wrong credentials |
| **stale** | Was true once, not anymore | "Index out of date", "stale lock", "file modified since read" |
| **unknown** | Cannot classify from the message alone | Generic exception, empty error, "something went wrong" |
3. **Pick one of five recovery actions** based on the bucket:
| Bucket | Default action | When to deviate |
|---|---|---|
| **transient** | `retry-with-backoff` (see next skill) | Never skip the backoff. If retries exceed the budget, escalate to `ask-user`. |
| **deterministic** | `switch` (try an alternative tool) or `fallback` (degrade gracefully) | If no alternative exists, `ask-user`. |
| **stale** | `refresh-then-retry` (re-read state, then retry once) | If still failing after one refresh, escalate to `ask-user`. |
| **unknown** | `ask-user` (or `skip-with-warning` if user signal allowed it) | Never silently retry an unknown error. |
4. **Execute the chosen action explicitly** — do not bundle it with other tool calls.
The user must be able to see "I retried" / "I switched to X" / "I asked you" as a discrete
step in the response.
5. **Record the decision in the response** so the user can audit:
```text
Recovery decision: <action>
Reason: <one-line reason, citing the bucket>
```
6. **After the action**, re-evaluate. If the action also failed, re-categorize (the bucket
may have changed — e.g. a "transient" error that persists for 5 retries is now a
"deterministic" error in practice) and pick a new action.
## Output contract
The user sees, in this order:
- One-line error summary (what went wrong, with the tool / file / op named).
- Bucket classification: `transient` / `deterministic` / `stale` / `unknown`.
- Chosen action: `retry` / `switch` / `fallback` / `refresh-then-retry` / `ask-user` / `skip`.
- One-line reason citing the bucket.
- (If retry) the backoff plan: "N attempts, M seconds between, exponential with jitter."
- (If ask) the user-facing question with concrete options.
- (If fallback / skip) what degraded behaviour the user is now getting.
## Example
```text
> bash(command="cat /etc/hosts")
Error: cat: /etc/hosts: Permission denied
Recovery decision: switch
Reason: bucket=deterministic (permission denied won't change on retry);
switching to `read` with explicit `path=/etc/hosts` (read may have different
permission semantics than shell cat) before asking the user.
```
```text
> bash(command="curl https://internal-api.example.com/health")
Error: connect ECONNREFUSED 10.0.0.5:443
Recovery decision: retry
Reason: bucket=transient (network refused); will retry 3 times with 2s/4s/8s backoff
and 500ms jitter; if all fail, escalate to ask-user.
```
```text
> task(agent_name="explore", prompt="...")
Status: closed-failed. Sub-agent error: "context window exceeded".
Recovery decision: ask-user
Reason: bucket=unknown (sub-agent did not return a clear error class); do not silently
retry with a smaller brief; surface to user with options:
(a) reduce the sub-task scope
(b) switch to a model with larger context
(c) skip this sub-task
```
## Common pitfalls
- **Do not default to retry.** Retry is only correct for `transient` (and a few `stale`).
For `deterministic` and `unknown`, retry is the most expensive wrong answer.
- **Do not bundle the recovery with other tool calls.** A retry hidden inside a larger
batch of work is invisible. Always surface the recovery as a discrete step.
- **Do not re-categorize silently.** If you categorize as `transient`, retry 3 times,
and it still fails, the bucket is now `deterministic` or `unknown` — say so out loud.
- **Do not ask the user a vague question.** "What should I do?" is not an option. Give
the user 2-4 concrete options based on the bucket.
- **Do not skip-with-warning without permission.** The user did not pre-authorize
silent skips. If the work is optional, the user should have said so at the start.
- **Do not blame the tool.** The tool did what it was told. Categorize the error
honestly, not defensively.
- **Do not loop on retry forever.** Always have a max-attempt budget; on exhaustion,
escalate to `ask-user`.
## Verification checklist
- [ ] Did you categorize the error into one of four buckets before picking an action?
- [ ] Did you pick one of five actions based on the bucket (not the default)?
- [ ] Did you state the recovery decision in the response, with the bucket and reason?
- [ ] (Retry) Did you specify the backoff plan (attempts, intervals, jitter)?
- [ ] (Ask) Did you give 2-4 concrete options, not "what should I do?"
- [ ] (Switch / Fallback) Did you name the alternative tool / the degraded behaviour?
- [ ] (Skip) Did you confirm the user pre-authorized this work as optional?
- [ ] Did you re-evaluate after the action and re-categorize if it failed?
- [ ] Is the recovery step a discrete line in the response (not bundled)?
GitHub에서 보기