Is Sonarr Down? Real-Time Status & Outage Checker
Is Sonarr Down? Real-Time Status & Outage Checker
Sonarr is an open-source TV series download manager with 10,000+ GitHub stars, built by the *arr suite community. It monitors RSS feeds from Usenet and BitTorrent indexers to automatically grab, sort, rename, and organize TV show episodes as they air. Sonarr integrates with download clients (qBittorrent, SABnzbd, NZBGet, Deluge, Transmission) and media servers (Plex, Jellyfin, Emby) to deliver a fully automated TV library pipeline. Home media server enthusiasts worldwide rely on Sonarr running continuously — when it goes down, new episode grabs stop, download imports stall, and media servers stop receiving fresh content.
Sonarr exposes a full REST API on port 8989. Monitoring both the process and the API health endpoint is the fastest way to catch failures before they snowball into missed episodes or a backlog of unimported files.
Quick Status Check
#!/bin/bash
# Sonarr health check
# Usage: SONARR_API_KEY=your_key ./sonarr-check.sh
SONARR_HOST="${SONARR_HOST:-http://localhost:8989}"
SONARR_API_KEY="${SONARR_API_KEY:-your_api_key_here}"
PASS=0
FAIL=0
echo "=== Sonarr Health Check ==="
echo "Host: $SONARR_HOST"
echo ""
# 1. Check process is running
if pgrep -x "Sonarr" > /dev/null 2>&1 || pgrep -f "Sonarr.exe" > /dev/null 2>&1; then
echo "[OK] Sonarr process is running"
PASS=$((PASS+1))
else
echo "[FAIL] Sonarr process not found"
FAIL=$((FAIL+1))
fi
# 2. Check port 8989 is open
if nc -z localhost 8989 2>/dev/null; then
echo "[OK] Port 8989 is open"
PASS=$((PASS+1))
else
echo "[FAIL] Port 8989 is not reachable"
FAIL=$((FAIL+1))
fi
# 3. Check system status API
STATUS=$(curl -sf --max-time 10 \
-H "X-Api-Key: $SONARR_API_KEY" \
"$SONARR_HOST/api/v3/system/status")
if [ $? -eq 0 ]; then
VERSION=$(echo "$STATUS" | grep -o '"version":"[^"]*"' | cut -d'"' -f4)
echo "[OK] API responding — Sonarr v$VERSION"
PASS=$((PASS+1))
else
echo "[FAIL] /api/v3/system/status did not respond"
FAIL=$((FAIL+1))
fi
# 4. Check health endpoint for WARNING/ERROR items
HEALTH=$(curl -sf --max-time 10 \
-H "X-Api-Key: $SONARR_API_KEY" \
"$SONARR_HOST/api/v3/health")
if [ $? -eq 0 ]; then
ISSUE_COUNT=$(echo "$HEALTH" | grep -o '"type":"' | wc -l | tr -d ' ')
if [ "$ISSUE_COUNT" -eq 0 ]; then
echo "[OK] Health check clean — no issues reported"
else
echo "[WARN] Health check returned $ISSUE_COUNT issue(s):"
echo "$HEALTH" | grep -o '"message":"[^"]*"' | cut -d'"' -f4 | while read -r msg; do
echo " - $msg"
done
fi
PASS=$((PASS+1))
else
echo "[FAIL] /api/v3/health did not respond"
FAIL=$((FAIL+1))
fi
echo ""
echo "=== Result: $PASS passed, $FAIL failed ==="
[ "$FAIL" -eq 0 ] && exit 0 || exit 1
Python Health Check
#!/usr/bin/env python3
"""
Sonarr health check
Checks system status, health issues, download queue, missing episodes, and series count.
"""
import os
import sys
import json
import urllib.request
import urllib.error
SONARR_HOST = os.environ.get("SONARR_HOST", "http://localhost:8989")
SONARR_API_KEY = os.environ.get("SONARR_API_KEY", "your_api_key_here")
HEADERS = {
"X-Api-Key": SONARR_API_KEY,
"Accept": "application/json",
}
results = []
failures = 0
def check(label, ok, detail=""):
global failures
status = "OK " if ok else "FAIL"
if not ok:
failures += 1
msg = f"[{status}] {label}"
if detail:
msg += f" — {detail}"
results.append(msg)
print(msg)
def api_get(path, timeout=10):
url = f"{SONARR_HOST}{path}"
req = urllib.request.Request(url, headers=HEADERS)
try:
with urllib.request.urlopen(req, timeout=timeout) as resp:
return json.loads(resp.read().decode())
except urllib.error.HTTPError as e:
raise RuntimeError(f"HTTP {e.code} from {path}")
except Exception as e:
raise RuntimeError(f"Request failed: {e}")
print("=== Sonarr Python Health Check ===")
print(f"Host: {SONARR_HOST}\n")
# 1. System status — version and OS
try:
status = api_get("/api/v3/system/status")
version = status.get("version", "unknown")
branch = status.get("branch", "unknown")
os_name = status.get("osName", "unknown")
check("System status API", True, f"v{version} ({branch}) on {os_name}")
except RuntimeError as e:
check("System status API", False, str(e))
# 2. Health endpoint — list any WARNING or ERROR items
try:
health = api_get("/api/v3/health")
issues = [h for h in health if h.get("type") in ("warning", "error")]
if not issues:
check("Health endpoint", True, "no issues reported")
else:
check("Health endpoint", False, f"{len(issues)} issue(s) found")
for issue in issues:
print(f" [{issue.get('type','?').upper()}] {issue.get('message','')}")
except RuntimeError as e:
check("Health endpoint", False, str(e))
# 3. Download queue — count of active items
try:
queue = api_get("/api/v3/queue")
total = queue.get("totalRecords", 0)
check("Download queue", True, f"{total} item(s) in queue")
except RuntimeError as e:
check("Download queue", False, str(e))
# 4. Wanted missing — episodes Sonarr hasn't been able to grab
try:
missing = api_get("/api/v3/wanted/missing?pageSize=1")
total_missing = missing.get("totalRecords", 0)
ok = total_missing < 500
check(
"Wanted/missing episodes",
ok,
f"{total_missing} missing episode(s)"
+ ("" if ok else " — unusually high, check indexers"),
)
except RuntimeError as e:
check("Wanted/missing episodes", False, str(e))
# 5. Series count — confirms database is accessible and populated
try:
series = api_get("/api/v3/series")
count = len(series) if isinstance(series, list) else 0
check("Series library", True, f"{count} series tracked")
except RuntimeError as e:
check("Series library", False, str(e))
# Summary
print(f"\n=== Result: {len(results) - failures} passed, {failures} failed ===")
sys.exit(0 if failures == 0 else 1)
Common Sonarr Outage Causes
| Symptom | Likely Cause | Resolution |
|---|---|---|
| Episodes searched but never download | Download client disconnected or credentials changed | Settings → Download Clients → test connection; re-enter password if changed |
| No new episodes found despite airing | Indexer unreachable or returning no results | Settings → Indexers → test each indexer; check Prowlarr sync if used |
| Sonarr crashes on startup | SQLite database corruption after unclean shutdown | Stop Sonarr; run sqlite3 sonarr.db "PRAGMA integrity_check"; restore from backup |
| Download client rejects connections | Authentication failure — API key or password rotated | Update credentials in Settings → Download Clients; verify username/password match |
| Completed downloads not importing | Disk full — import path has no free space | Free disk space on the target drive; check df -h; adjust path if needed |
| Episodes stuck in download folder indefinitely | Rename/move task failing — permissions or path mismatch | Check Sonarr logs for import errors; verify read/write permissions on media folder |
Architecture Overview
| Component | Function | Failure Impact |
|---|---|---|
| Sonarr Core (C#/.NET) | Main process — scheduling, API, import logic | Total failure; all grabs and imports stop |
| SQLite Database | Stores series, episodes, history, and quality profiles | Crash on startup; episode tracking lost if corrupted |
| Indexer RSS Engine | Polls RSS feeds to detect new episode releases | No new grabs; existing downloads unaffected |
| Download Client Integration | Sends NZB/torrent to qBittorrent, SABnzbd, etc. | Episodes found but never sent to downloader |
| Import/Rename Engine | Moves completed downloads into library with correct naming | Downloads complete but don't appear in media server |
| Media Server Notification | Triggers Plex/Jellyfin/Emby library scan after import | Files present but media server doesn't show new episodes |
Uptime History
| Date | Incident Type | Duration | Impact |
|---|---|---|---|
| 2026-01 | SQLite corruption after power loss | ~3 hrs (restore from backup) | Sonarr offline; episode history and series config lost until restore |
| 2025-10 | Download client credential rotation | ~12 hrs undetected | All grabs queued internally but never sent to qBittorrent |
| 2025-08 | Indexer outage (multiple providers) | ~6 hrs | New episode searches returned zero results; backlog built up |
| 2025-07 | Disk full on media drive | ~2 hrs | Completed downloads not imported; Sonarr logged import errors silently |
Monitor Sonarr Automatically
Sonarr failures are silent by default — the process may be running but the download client connection is broken, or disk space is exhausted, and no new episodes are being imported without any visible alert. ezmon.com monitors your Sonarr endpoints from multiple external probes and alerts your team via Slack, PagerDuty, or SMS the moment the API stops responding or health checks report critical errors.