Keepit Backup Failure Root Cause Analyzer
Overview
The Backup Failure Root Cause Analyzer is a diagnostic skill that systematically investigates why Keepit backup jobs have failed, correlates failures with environmental changes, classifies root causes, and provides actionable remediation guidance. It combines job history analysis, error parsing, audit log correlation, health checks, and snapshot gap assessment to deliver comprehensive failure investigations.
Target Persona: Backup Administrators, IT Managers, Support Engineers
Primary Use Cases:
- Investigating why a specific backup job failed
- Diagnosing recurring backup failures across connectors
- Correlating failures with configuration or environmental changes
- Assessing data risk from backup gaps caused by failures
- Generating remediation steps and post-fix verification checklists
Trigger Keywords:
- "why did backup fail", "root cause", "backup error"
- "failure investigation", "troubleshoot backup"
- "diagnose failure", "backup not working"
- "backup keeps failing", "recurring failure"
- "what caused the backup error"
Core Workflow
Step 1: Identify the Failure
Retrieve job history for the target connector and isolate failed jobs.
# Get recent job history for the connector
jobs = get_job_history(guid=connector['guid'], duration="P7D")
# Filter to failed jobs — jobs with a 'failed' timestamp
failed_jobs = [j for j in jobs if j.get('failed')]
# Sort by failure time, most recent first
failed_jobs.sort(key=lambda j: j['failed'], reverse=True)
# If user asked about a specific failure, match by time or description
# Otherwise, investigate the most recent failure
target_failure = failed_jobs[0] if failed_jobs else None
If no failed jobs are found in the requested window, expand the search:
# Expand to 30 days if no failures in 7 days
if not failed_jobs:
jobs = get_job_history(guid=connector['guid'], duration="P30D")
failed_jobs = [j for j in jobs if j.get('failed')]
Step 2: Parse Error Details
Extract structured error information from the execsummary XML field.
# Parse the execsummary XML for error details
from scripts.rootcause_utils import parse_execsummary
execsummary = parse_execsummary(target_failure.get('execsummary', ''))
# Key fields extracted:
# - execsummary['errors'] → List of error messages
# - execsummary['exit_reason'] → Why the job terminated
# - execsummary['warnings'] → Warning messages preceding failure
# - execsummary['details'] → Additional context fields
Step 3: Gather Surrounding Context
Pull audit log events around the failure time window for correlation.
# Get audit events from the past 30 days
audit_logs = get_audit_log_history(duration="P30D")
# Correlate events within +/- 24 hours of the failure
from scripts.rootcause_utils import correlate_failure_with_audit
correlation = correlate_failure_with_audit(
failure_time=target_failure['failed'],
audit_events=audit_logs,
window_hours=24
)
# correlation['events_before'] → Events leading up to failure
# correlation['events_after'] → Events after the failure
# correlation['config_changes'] → Configuration modifications
# correlation['auth_events'] → Authentication-related events
# correlation['total_correlated'] → Count of correlated events
Step 4: Check Current State
Verify whether the connector is still in a failed/unhealthy state.
# Check connector health status
health = get_connector_health(guid=connector['guid'])
# Possible states:
# - "healthy" → Connector recovered on its own
# - "unhealthy" → Still broken, needs attention
# - "critical" → Critical issues, needs immediate attention
# - "unknown" → Cannot determine state
Step 5: Check Active Recovery
Determine if a retry or recovery job is already running.
# Check for active jobs (retry in progress?)
active = get_active_jobs(guid=connector['guid'])
# If active jobs exist, a retry may already be underway
# Report this to avoid duplicate remediation efforts
if active:
print(f"Recovery job detected: {active[0].get('description', 'Unknown')}")
print(f"Started: {active[0].get('started', 'Unknown')}")
Step 6: Assess Data Impact
Calculate the backup gap and data at risk since the last successful backup.
# Get the latest successful snapshot
latest = get_latest_snapshot(guid=connector['guid'])
# Get snapshot history for gap analysis
snapshots = get_snapshot_range(guid=connector['guid'], timespan="P30D", count=99)
# Assess data risk
from scripts.rootcause_utils import assess_data_risk
risk = assess_data_risk(latest_snapshot=latest, snapshot_range=snapshots)
# risk['gap_hours'] → Hours since last good backup
# risk['gap_description'] → Human-readable gap description
# risk['risk_level'] → "low" / "medium" / "high" / "critical"
# risk['last_good_backup'] → Timestamp of last successful backup
# risk['data_at_risk_description'] → What data may be unprotected
Step 7: Correlate Failure with Changes
Determine if configuration changes caused or contributed to the failure.
# Get all connectors for cross-reference
connectors = get_cloud_connectors(connectorType="cloud")
# Check if config changes caused the failure
from scripts.rootcause_utils import detect_config_change_causality
causality = detect_config_change_causality(
failure_time=target_failure['failed'],
audit_events=audit_logs,
connectors=connectors
)
# causality['causal_likely'] → True/False
# causality['changes_found'] → List of relevant changes
# causality['time_delta'] → Time between change and failure
# causality['confidence'] → "high" / "medium" / "low"
# causality['description'] → Human-readable causality assessment
Step 8: Classify and Attribute
Categorize the root cause and assign confidence level.
from scripts.rootcause_utils import classify_failure_type, classify_recurrence
# Classify the failure type
classification = classify_failure_type(
job=target_failure,
execsummary_parsed=execsummary
)
# classification['type'] → "auth_expired", "config_change", "api_limit",
# "connectivity", "permission_denied",
# "quota_exceeded", "service_unavailable", "unknown"
# classification['confidence'] → "high" / "medium" / "low"
# classification['indicators'] → Evidence supporting classification
# classification['description'] → Human-readable explanation
# Determine if this is a recurring issue
recurrence = classify_recurrence(
job_history=jobs,
current_failure=target_failure
)
# recurrence['classification'] → "first" / "recurring" / "chronic"
# recurrence['occurrence_count'] → Number of similar failures
# recurrence['first_seen'] → When this pattern first appeared
# recurrence['pattern_description'] → Description of the failure pattern
Step 9: Generate Resolution Steps
Produce type-specific remediation guidance.
from scripts.rootcause_utils import generate_resolution_steps
# Build context for resolution generation
context = {
'connector': connector,
'health': health,
'execsummary': execsummary,
'causality': causality,
'recurrence': recurrence,
'risk': risk
}
steps = generate_resolution_steps(
failure_type=classification['type'],
context=context
)
# Each step contains:
# - step['number'] → Step order
# - step['action'] → Brief action title
# - step['detail'] → Detailed instructions
# - step['priority'] → "critical" / "high" / "medium" / "low"
Step 10: Provide Verification Checklist
Generate post-fix validation steps to confirm the issue is resolved.
from scripts.rootcause_utils import generate_verification_checklist
checklist = generate_verification_checklist(
failure_type=classification['type']
)
# Each checklist item:
# - item['check'] → What to verify
# - item['how_to_verify'] → How to perform the check
# - item['expected_result'] → What success looks like
Output Formatting Guidelines
Failure Investigation Header
# Backup Failure Root Cause Analysis
**Connector:** {connector_name} ({connector_type})
**Failure Time:** {failure_timestamp}
**Investigation Time:** {now}
**Status:** {current_health_status}
Root Cause Classification Display
Use severity icons to indicate urgency:
- ❌ Critical — Backup completely non-functional, data at risk
- ⚠️ Warning — Backup degraded, intermittent failures
- ✅ Resolved — Issue has been corrected, backup operational
Use priority icons for resolution steps:
- 🔴 High Priority — Address immediately
- 🟡 Medium Priority — Address within 24 hours
- 🟢 Low Priority — Schedule for next maintenance window
Summary Table Format
| Field | Value |
|-------|-------|
| Root Cause | {classification_type} |
| Confidence | {confidence_level} |
| Recurrence | {first / recurring / chronic} |
| Backup Gap | {gap_hours}h ({gap_description}) |
| Risk Level | {risk_icon} {risk_level} |
| Active Recovery | {yes/no} |
Timeline Display
## Event Timeline
| Time | Event | Relevance |
|------|-------|-----------|
| {t-2h} | Retention policy updated | 🔴 Likely cause |
| {t-0} | Backup job failed | ❌ Target failure |
| {t+1h} | Retry job started | ✅ Auto-recovery |
Resolution Steps Format
## Resolution Steps
### 🔴 Step 1: {action_title}
{detailed_instructions}
### 🟡 Step 2: {action_title}
{detailed_instructions}
### 🟢 Step 3: {action_title}
{detailed_instructions}
Verification Checklist Format
## Post-Fix Verification Checklist
- [ ] {check_description}
- **How:** {how_to_verify}
- **Expected:** {expected_result}
Advanced Features
Automatic Time-Window Correlation
The skill automatically correlates audit events with failure timing:
- -24h to failure: Events that may have caused the failure
- Failure to +24h: Events that may indicate recovery or further degradation
- Config changes within 4h: High-confidence causal attribution
- Auth events within 24h: Potential token/credential issues
Config Change Attribution
When audit logs show configuration changes near the failure time:
# Example: "Retention policy changed 2h before first failure"
if causality['causal_likely'] and causality['confidence'] == 'high':
report += f"⚠️ Configuration change detected {causality['time_delta']} before failure\n"
report += f" Change: {causality['changes_found'][0]['description']}\n"
report += f" Recommendation: Review and potentially revert this change\n"
Failure Classification Categories
| Category | Indicators | Typical Resolution |
|---|---|---|
auth_expired |
Token expired, 401 errors, auth failure messages | Refresh or reauthorize credentials |
config_change |
Recent config audit events, retention changes | Review and revert recent changes |
api_limit |
Rate limit errors, 429 responses, throttling | Adjust backup schedule, stagger jobs |
connectivity |
Timeout errors, DNS failures, connection refused | Check network, firewall, DNS settings |
permission_denied |
403 errors, access denied messages | Review and update service account permissions |
quota_exceeded |
Storage quota, license limit messages | Increase quota or remove stale data |
service_unavailable |
503 errors, maintenance messages | Wait and retry, check vendor status page |
unknown |
No clear indicators | Escalate to support with full diagnostic |
Recurring vs. New Failure Detection
# Classification thresholds
# 1 occurrence → "first" — Investigate root cause
# 2-4 occurrences → "recurring" — Establish pattern, prioritize fix
# 5+ occurrences → "chronic" — Escalate, systemic issue
Data Risk Assessment Thresholds
| Gap Duration | Risk Level | Icon | Action |
|---|---|---|---|
| < 24 hours | Low | 🟢 | Monitor, standard remediation |
| 24-72 hours | Medium | 🟡 | Prioritize fix, notify stakeholders |
| 72-168 hours | High | 🔴 | Urgent remediation required |
| > 168 hours | Critical | ❌ | Emergency response, executive notification |
Error Handling
No Failed Jobs Found
✅ No backup failures detected for {connector_name} in the past {duration}.
All recent jobs completed successfully. If you believe a failure occurred,
try expanding the search window:
- "Check for failures in the last 30 days"
- "Show all job history for this connector"
Execsummary Parse Failure
⚠️ Could not parse error details from job execution summary.
The job record indicates a failure at {failure_time}, but the error details
could not be extracted. This may indicate a truncated or malformed record.
**Available information:**
- Job failed: {failure_timestamp}
- Job description: {description}
- Connector: {connector_name}
**Recommendation:** Check Keepit admin console for detailed error logs.
Insufficient Audit Data
⚠️ Limited audit log data available for correlation.
Only {count} audit events found in the correlation window.
Root cause analysis may be incomplete without full audit context.
**Proceeding with available data...**
Connector Not Found
❌ Connector "{connector_name}" not found.
Please verify the connector name or GUID. Available connectors:
{list_of_connectors}
Best Practices
Investigation Approach
- Start with the most recent failure — It has the freshest context and audit data
- Always check current health first — The issue may already be resolved
- Correlate before concluding — Never attribute root cause without checking audit logs
- Assess recurrence — A first-time failure is different from a chronic one
- Quantify data risk — Stakeholders need to know impact, not just cause
Escalation Guidelines
- First occurrence, low risk: Standard remediation, monitor
- Recurring, medium risk: Escalate to team lead, create tracking ticket
- Chronic, high risk: Escalate to management, schedule dedicated investigation
- Any critical risk: Immediate notification to data protection officer
Communication Guidelines
- Lead with impact: "Your Exchange backup has a 48-hour gap" before "Token expired"
- Provide time context: "This started failing 2 hours after the retention policy change"
- Be specific about remediation: "Re-authorize the Microsoft 365 connector" not "Fix auth"
- Include verification: "After fixing, run a manual backup and confirm it succeeds"
Common User Requests
"Why did my backup fail?"
- Identify the connector and most recent failure
- Parse error details from execsummary
- Classify the failure type
- Provide root cause with confidence level
- Give resolution steps
"Is this a recurring issue?"
- Pull 30-day job history
- Classify recurrence pattern
- Show failure timeline with dates
- Identify if pattern exists (e.g., every Monday)
- Recommend schedule or configuration changes
"What data am I missing?"
- Get latest snapshot timestamp
- Calculate backup gap
- Assess risk level
- Describe what data may be unprotected
- Provide urgency context
"Was it caused by the config change?"
- Pull audit logs around failure time
- Run config change causality analysis
- Show timeline of changes vs. failures
- Provide confidence assessment
- Recommend revert if causal
"What do I need to fix?"
- Complete root cause analysis
- Generate type-specific resolution steps
- Prioritize by urgency
- Provide verification checklist
- Estimate time to resolution
"Give me a full RCA report"
- Run complete 10-step workflow
- Format as structured report with all sections
- Include timeline, classification, impact, resolution
- Add verification checklist
- Provide executive summary
Cross-Skill Investigation Workflows
With Job History Analyzer
When failure investigation requires broader job trend context:
# Use job-history-analyzer patterns for trend detection
# Then drill into specific failures with this skill
jobs = get_job_history(guid=connector['guid'], duration="P30D")
# Analyze success/failure trends, then investigate individual failures
With Account Health Skill
When failure may be part of a broader account health issue:
# Check overall account health for systemic problems
health = get_connector_health(guid=connector['guid'])
# If multiple connectors are unhealthy, this may be an account-level issue
connectors = get_cloud_connectors(connectorType="cloud")
With Compliance Audit Log
When investigation requires detailed audit trail:
# Get comprehensive audit history for compliance-grade investigation
audit_logs = get_audit_log_history(duration="P30D")
# Use for change management correlation and compliance reporting
With Snapshot Analyzer
When failure impact requires detailed snapshot gap analysis:
# Deep dive into snapshot history for precise gap measurement
snapshots = get_snapshot_range(guid=connector['guid'], timespan="P30D", count=99)
latest = get_latest_snapshot(guid=connector['guid'])
# Combine with failure timeline for complete impact picture
With Retention Policy Auditor
When config change causality involves retention policies:
# Cross-reference retention policy changes with failure timing
connectors = get_cloud_connectors(connectorType="cloud")
# Check retention_updated fields against failure timestamps
Skill Integration Points
| Skill | Integration | When to Use |
|---|---|---|
| Job History Analyzer | Trend context for failures | Recurring failures, pattern detection |
| Account Health | Systemic health check | Multiple connector failures |
| Compliance Audit Log | Detailed change tracking | Config change attribution |
| Snapshot Analyzer | Precise gap measurement | Data risk assessment |
| Retention Policy Auditor | Policy change correlation | Retention-related failures |
| Security Incident Investigator | Auth event correlation | Authentication failures |
| Executive Backup Summary | Impact reporting | Management escalation |
Technical Notes
MCP Functions Used
| Function | Purpose | Parameters |
|---|---|---|
get_job_history |
Retrieve job records | guid, duration (ISO 8601) |
get_audit_log_history |
Retrieve audit events | duration |
get_connector_health |
Check connector status | guid |
get_active_jobs |
Check running jobs | guid |
get_latest_snapshot |
Get most recent snapshot | guid |
get_snapshot_range |
Get snapshot history | guid, timespan, count |
get_cloud_connectors |
List all connectors | connectorType="cloud" |
Time Calculations
- Failure time parsing: ISO 8601 format (
2025-01-15T08:30:00Z) - Correlation window: Default +/- 24 hours from failure time
- Config change window: High confidence within 4 hours, medium within 24 hours
- Backup gap: Difference between
nowand last successful snapshot - Recurrence window: 30 days for pattern detection
- Duration formats: ISO 8601 durations (
P7D= 7 days,P30D= 30 days)
Error Resilience
- Missing execsummary: Fall back to job-level metadata (description, timestamps)
- Empty audit logs: Proceed with job-only analysis, note limited correlation
- Connector health unavailable: Skip health check, note in report
- Snapshot data missing: Estimate gap from job history timestamps
- Parse failures: Catch XML parse errors, return raw data with error flag
- API timeouts: Retry once, then proceed with partial data and note gaps
Success Metrics
| Metric | Target | Measurement |
|---|---|---|
| Root cause identified | 85%+ of investigations | Classification != "unknown" |
| Correct classification | 90%+ accuracy | User confirms resolution worked |
| Resolution provided | 100% of investigations | Steps generated for all types |
| Time to diagnosis | < 30 seconds | From query to full RCA report |
| Correlation accuracy | 80%+ | Config changes correctly attributed |
| Risk assessment accuracy | 90%+ | Gap calculation matches reality |