Files
cleveragents-core/docs/reference/error_recovery.md
T
CoreRasurae 007af498b8
CI / benchmark-publish (pull_request) Has been skipped
CI / build (pull_request) Successful in 17s
CI / helm (pull_request) Successful in 33s
CI / lint (pull_request) Successful in 3m42s
CI / security (pull_request) Successful in 4m8s
CI / quality (pull_request) Successful in 4m9s
CI / typecheck (pull_request) Successful in 4m20s
CI / integration_tests (pull_request) Successful in 7m2s
CI / unit_tests (pull_request) Successful in 7m55s
CI / docker (pull_request) Successful in 1m19s
CI / coverage (pull_request) Successful in 8m46s
CI / e2e_tests (pull_request) Successful in 16m1s
CI / status-check (pull_request) Successful in 1s
CI / build (push) Successful in 17s
CI / helm (push) Successful in 22s
CI / quality (push) Successful in 31s
CI / lint (push) Successful in 3m28s
CI / typecheck (push) Successful in 3m54s
CI / benchmark-regression (push) Has been skipped
CI / security (push) Successful in 4m5s
CI / integration_tests (push) Successful in 6m13s
CI / unit_tests (push) Successful in 6m28s
CI / docker (push) Successful in 1m34s
CI / coverage (push) Successful in 12m5s
CI / e2e_tests (push) Successful in 18m47s
CI / status-check (push) Successful in 1s
CI / benchmark-publish (push) Successful in 28m0s
CI / benchmark-regression (pull_request) Successful in 59m48s
refactor(autonomy): rename automation profile task flags to spec names
Renamed all 11 task-type confidence threshold fields in AutomationProfile
from phase-transition semantics to spec-defined task-type semantics.
Updated all 8 built-in profiles, CLI formatting, YAML schema, services,
and all Behave/Robot tests referencing the old field names.

Post-review fixes:
- Fixed 24 stale old field names in M6 fixture files
  (automation_profiles.json, autonomy_guardrails.json)
- Added model_validator(mode='before') to detect legacy field names
  and raise actionable ValueError with rename mapping
- Added semantic bridge comments in PlanLifecycleService mapping
  task-type thresholds to phase-transition gates
- Added threshold_field to structured log messages for observability
- Restored categorised CLI automation-profile show output to match
  spec (Phase Transitions / Decision Automation / Self-Repair /
  Execution Controls) instead of flat list
- Added missing access_network field to spec show output examples
  (Rich, Plain, JSON, YAML variants)
- Aligned ADR-017 profile fields table to all 11 fields with
  descriptions matching spec Automatable Tasks table
- Aligned automation_profiles.md threshold descriptions with spec
- Added spec section references in phase_reversion.md, error_recovery.md,
  and plan_execute.md for field naming context
- Extended repository roundtrip test to assert all 11 threshold fields
- Fixed benchmark _make_profile() passing safety fields as top-level
  kwargs instead of via SafetyProfile sub-model (incompatible with
  extra="forbid")
- Aligned CLI JSON/YAML output structure for automation-profile show
  with the specification grouped format (phase_transitions,
  decision_automation, self_repair, execution_controls)
- Moved safety boolean fields into the Execution Controls section
  of Rich output per spec examples
- Reverted auto profile description to "Fully automatic except apply"
  per specification (line 16703, line 28406)
- Improved bridge comments in test steps with semantic context for
  threshold-to-gate mappings

ISSUES CLOSED: #902
2026-03-30 13:18:07 +01:00

9.0 KiB

Error Recovery Reference

This document describes the error recovery patterns, error classification, recovery hint system, and retry policy logic added in D1b.recovery.

Error Categories

Errors are classified into categories that determine recovery behaviour:

Category Retriable Description
transient Yes Temporary failures (network, timeout, rate-limit)
validation Yes Validation failures during Execute or Apply
configuration No Bad config, missing required fields
resource No Missing or conflicting resources
merge_conflict Yes Sandbox merge failures
authentication No Auth/authz failures
provider Yes LLM provider errors (model unavailable, token limit)
internal No Unexpected internal errors (bugs)
unknown No Unclassified errors

Recovery Actions

Each error category maps to one or more recovery actions with CLI commands:

Action CLI Command When Used
retry agents plan prompt <plan_id> Transient / provider errors
correct agents plan correct <plan_id> Validation failures
revert_strategize agents plan revert <plan_id> --to-phase strategize Resource / merge conflicts
prompt agents plan prompt <plan_id> Resume with guidance
cancel agents plan cancel <plan_id> Non-recoverable errors
manual Internal errors (check logs)

Retry Policy

The retry policy is controlled by the automation profile's modify_config threshold (named per spec § Automatable Tasks):

  • 0.0 (auto): Automatic retry for retriable errors
  • 1.0 (human): Always escalate to human
Error occurs → classify_error(message, exception_type)
    |
    +→ retriable category? → retry_count < max_retries? → threshold < 1.0?
    |     |                     |                            |
    |     No → escalate         No → exhausted, escalate     No → escalate
    |                                                        |
    |                                                        Yes → auto retry
    |
    +→ non-retriable → escalate immediately

Retry Limits

Default max_retries = 3. Configured via SubplanConfig.max_retries for subplans (max: 5).

Retry Exhaustion

When all retry attempts are used, the error is escalated with:

  • Clear message indicating retries exhausted
  • Recovery hints for manual intervention
  • Error history preserved for debugging

Structured Error Metadata

When an error is recorded, the following metadata is stored in the plan's error_details field:

Key Type Description
error_category string Classification category
error_phase string Phase when error occurred
retry_count string Number of retries attempted
max_retries string Maximum retries allowed
is_retriable string Whether error can be retried
error_actor string Actor involved (if any)
error_tool_call string Tool call that failed (if any)
stack_summary string Abbreviated stack trace (last 3 frames)
recovery_action string Suggested recovery action
recovery_hint string Human-readable recovery message
recovery_command string CLI command for recovery

Execute Phase Integration

The PlanExecutor accepts an optional ErrorRecoveryService and uses it during the Execute phase to record errors and drive automatic retries:

PlanExecutor
├── StrategizeStubActor   (records errors via ErrorRecoveryService)
├── ExecuteStubActor      (retry loop driven by ErrorRecoveryService)
├── PlanLifecycleService  (phase transitions, persistence)
└── ErrorRecoveryService  (optional — error recording + retry policy)

Retry Loop

When error_recovery_service is provided, run_execute() wraps the execute actor in a retry loop:

  1. The actor runs.
  2. On failure the error is recorded via ErrorRecoveryService.record_error().
  3. should_retry() is checked — if the error is retriable and retries remain, the actor runs again.
  4. If retries are exhausted or the error is non-retriable, the plan transitions to ERRORED via fail_execute().

Strategize failures are also recorded through the service (but not retried — the strategize phase is read-only and failures are deterministic).

from cleveragents.application.services.plan_executor import PlanExecutor
from cleveragents.application.services.error_recovery_service import (
    ErrorRecoveryService,
)

er_service = ErrorRecoveryService(
    lifecycle_service=lifecycle,
    auto_retry_threshold=0.0,
    max_retries=3,
)

executor = PlanExecutor(
    lifecycle_service=lifecycle,
    tool_runner=runner,
    error_recovery_service=er_service,
)

# Execute with automatic retry on transient errors
result = executor.run_execute(plan_id)

CLI Commands

agents plan errors <plan_id>

Shows error decisions with recovery hints and retry history for a plan.

# Rich (default) output
agents plan errors 01HXYZ...

# JSON output
agents plan errors 01HXYZ... --format json

# Plain text
agents plan errors 01HXYZ... --format plain

Example rich output:

╭─ Plan Errors ──────────────────────────────────────────╮
│ Plan: 01HXYZ...                                        │
│ Phase: execute                                         │
│ State: errored                                         │
│ Error: RuntimeError: Connection timed out              │
│                                                        │
│ Error Category: transient                              │
│ Error Phase: execute                                   │
│ Retry Count: 3/3                                       │
│ Retriable: false                                       │
│                                                        │
│ Recovery Suggestions:                                  │
│   → Retry the operation — the failure was transient.   │
│     $ agents plan prompt 01HXYZ...                     │
╰────────────────────────────────────────────────────────╯

When no errors have been recorded the command shows a green confirmation message instead.

CLI Output

Recovery hints are included in CLI error output:

Error [transient]: Connection timed out after 30s
  Phase: execute
  Retry: 0/3
  Recovery suggestions:
    → Retry the operation — the failure was transient.
      $ agents plan prompt 01HXYZ...
  ✓ Automatic retry available.

Error History

The error history tracks all errors for a plan, including:

  • Total error count
  • Retry count per error
  • Category breakdown
  • Chronological error records with recovery hints

Note: Error history is held in-memory within the ErrorRecoveryService instance. If the service is restarted or a new instance is created, in-memory history is lost. The latest error metadata is also persisted to the plan's error_details field for durability across restarts.

Service API

ErrorRecoveryService

from cleveragents.application.services.error_recovery_service import (
    ErrorRecoveryService,
)

service = ErrorRecoveryService(
    lifecycle_service=lifecycle,
    auto_retry_threshold=0.0,  # from automation profile
    max_retries=3,
)

# Record an error
record = service.record_error(
    plan_id="01HXYZ...",
    phase="execute",
    message="Connection timed out",
    exception=exc,  # optional, for stack trace
)

# Check retry decision
if service.should_retry(plan_id):
    # auto-retry
    ...
elif service.should_escalate(plan_id):
    # show recovery hints to user
    hints = service.format_recovery_hints_for_cli(plan_id)
    print(hints)

# Get full error history
history = service.get_error_history(plan_id)
print(f"Total errors: {history.total_errors}")

# Format for CLI
output = service.format_error_output(plan_id, fmt="json")

PlanLifecycleService.update_error_details

External services use update_error_details() to merge structured error metadata into a plan's error_details field without accessing internal persistence methods:

lifecycle.update_error_details(plan_id, {
    "error_category": "transient",
    "retry_count": "2",
})

Domain Models

from cleveragents.domain.models.core.error_recovery import (
    ErrorCategory,
    ErrorRecord,
    ErrorHistory,
    ErrorRecoveryPolicy,
    RecoveryAction,
    RecoveryHint,
    classify_error,
    get_recovery_hints,
)

# Classify an error
category = classify_error("Connection timed out", "NetworkError")

# Get recovery hints
hints = get_recovery_hints(ErrorCategory.TRANSIENT, "01HXYZ...")

# Create a policy
policy = ErrorRecoveryPolicy(auto_retry_threshold=0.0, max_retries=3)
if policy.should_retry(record):
    ...