developer-tools

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

SymptomLikely CauseResolution
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

ComponentFunctionFailure 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

DateIncident TypeDurationImpact
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.

Set up Sonarr monitoring free at ezmon.com →

sonarrmedia-managementhome-serverself-hostedtv-downloadsstatus-checker