Troubleshooting - Kheopsian/Hydranos GitHub Wiki
Applies to Hydranos 4.4.
Find your symptom, read the likely cause, run the check, apply the fix; the explanation lives on the linked page. Text in code is quoted exactly as Hydranos prints it, so you can search your log for it.
First gather three facts:
-
Version: in the web UI header, next to Torrent Daemon; or
hydranos --version(Docker:docker exec hydranos hydranos --version) printshydranos 4.x.y. On Windows use the header:hydranos.exeis a windowed program whose--versiondoes not reach a console (from the code, untested). -
Log:
hydranos.lognext to yourdefault.toml, times in UTC. Docker:/config/hydranos.logordocker logs hydranos. systemd:/etc/hydranos/hydranos.logorjournalctl -u hydranos. Windows: besidehydranos.exe(with--config, beside that file), e.g.C:\Hydranos\hydranos.log; follow it in PowerShell withGet-Content C:\Hydranos\hydranos.log -Wait. The file rotates itself at 128 MiB (hydranos.log.1to.4). The Logs tab keeps only the last 2000 lines: for anything older, read the file. -
Health:
curl http://127.0.0.1:8199/healthanswersstarting,healthy,degraded(read itsproblems) orunhealthy(HTTP 503: the store does not answer, or no engine is listening for peers); in rescue mode, the plain textok(Monitoring and Logs).
Every stub and known bug of 4.4 is listed on Known Limitations in 4.4.
Cause: port 8199 opens at once; until the torrents are loaded the UI shows the startup screen and the API, login, the shim and /mcp answer 503 (Retry-After: 5) Hydranos is starting (<phase>): <restored> of <total> torrents restored. The log line hydra API ready ends it. Fix: wait; clients retry. A refused connection means the process is not running: read the log. See: While it starts on Operating Hydranos.
Cause: grep -q healthy also matches "unhealthy" (and the image has no curl). Fix: the bash probe on Docker Install, matching "status":"(healthy|degraded|starting)"; starting is HTTP 200, so no long start_period is needed. Docker does not restart an unhealthy container.
Cause: the config file is unreadable or not valid TOML. On Windows, "C:\Hydranos\data" in double quotes is a TOML escape error. Fix: write "C:/Hydranos/data" or 'C:\Hydranos\data'. See: Install on Windows, Configuration Reference.
Cause: a reverse proxy sent a public X-Forwarded-For, or the browser's address is not private (CGNAT/Tailscale 100.64.0.0/10 included). Fix: create the account once from the machine or your LAN (http://192.0.2.10:8199), or run hydranos reset-password '<password>' on the host, as the message says, and restart. See: Security and Access.
Fix: on the host, hydranos reset-password '<new password>' (8 characters at least; Docker: docker exec hydranos hydranos reset-password '…'), then restart Hydranos. On Windows quit Hydranos first; the command prints nothing there but writes the file. Or set password_hash = "" under [auth] while stopped: the Welcome to Hydranos screen returns. The API key does not change. See: Security and Access.
Cause: a wrong or old key. An empty key or the placeholder change-me-in-production is replaced at start; if default.toml cannot be written, the log says the API stays closed: an empty key then refuses every call, and the placeholder keeps working for anyone who knows it. Fix: copy [daemon] api_key from default.toml into your clients; in the second case make the file writable and restart. See: Security and Access.
Cause: default.toml has keys known to do nothing (3.x leftovers, listen_interfaces, [bench]…). Fix: do what Instead: says, delete the key. See: Upgrading from 3.x, Configuration Reference.
Cause: it opens until you click Skip in that browser (the choice is stored per browser) or an import adds at least one torrent. Fix: click Skip once; the wizard stays under Config › Advanced settings (default.toml) › Import › Import…. See: Migrating from qBittorrent.
Cause: the folders qBittorrent reports are not visible at the same path to Hydranos (another container, another mount). Fix: in the path mapping, set the right-hand column to the folder as Hydranos sees it, then Re-check paths until every row shows ✓. Hydranos inside gluetun cannot reach a LAN qBittorrent unless gluetun allows your LAN range. See: Step 3 on Migrating from qBittorrent.
Cause: every imported torrent goes to Hoard, whatever its category's mode, stopped by default. Only a torrent complete in qBittorrent whose content path exists after mapping skips the hash check. A re-run skips torrents already imported. Fix: look in Hoard, Start what should seed; for rechecks, fix the mapping. See: Migrating from qBittorrent.
Check: the list of failures shown at the end, or the log line import: torrent not added and its error; export … http 404 means this qBittorrent does not offer the export endpoint, http 409 (no metadata yet in qBittorrent) a magnet still without metadata there, (gave up after 4 attempts) a failure that kept coming back. Fix: fix the cause, then Retry the {n} failed. See: Migrating from qBittorrent.
Cause: 403 Forbidden. answers any call without a session: the login failed. Fails. (HTTP 200) means a wrong username, password or key, or a JSON body instead of a form. Check: curl -i --data-urlencode 'username=admin' --data-urlencode 'password=YOUR_PASSWORD' http://127.0.0.1:8199/api/v2/auth/login must answer Ok. with Set-Cookie: SID=…. Fix: admin account, or any username with the API key as password; port 8199, no URL base. See: qBittorrent Shim and Automation.
Cause: inside gluetun, Hydranos has no network of its own: the name hydranos resolves to nothing. Fix: host gluetun, port 8199, when the client shares a user-defined Docker network with gluetun; on Docker's default bridge network, the host's LAN address. See: VPN and Egress.
Adds fail with no save path: category "tv" is unknown and no savepath was given (the shim says Fails.)
Cause: the category is unknown or has no save path (one created by the client without savePath has none and is hoard), and the client sent no savepath and set no default folder with setPreferences save_path. Fix: create it on the Categories tab with a save path and the right Mode first. See: Categories and Routing.
Cause: Hydranos reports its own (container) paths. Fix: mount the same host folder at the same container path in both containers, or set a remote path mapping in the client. See: Docker Install, Migrating from qBittorrent.
Cause: since 4.4 the shim reports the real ratio, uploaded and seeding_time (4.3 sent 0): a client's own seed goal now fires, and can remove torrents. The limits it sends become Hydranos share limits, held until the tracker's declared Minimum seed is served, forever if it has none (log share limit reached, held: …). Queue positions answer 409 (use Force Start to run a torrent past the queue); file priority 0 is refused. Fix: set Minimum seed (0 included) on the Trackers tab. See: Queue, Share and Speed Limits, qBittorrent Shim and Automation.
Check: the message (no save path: …, no engine …, mode must be race or hoard …, <path>: no such file, race disk full: …, N file(s) of this torrent are already another torrent's with other bytes …, torrent already added, torrent file did not parse, this magnet has only a v2 info hash (btmh) …). Fix: see When an add is refused on Adding Torrents and Existing Data.
Cause: another torrent already names some of its files with other bytes, and [dedup] path_collision = "isolate" (default) gave it its own folder, <save path>/<first part of its name> [<first 8 hex digits of its hash>], reported as its save path. Files that verify are hardlinked in; seed mode is dropped. Fix: nothing, or path_collision = "refuse" under [dedup] and restart. See: Files another torrent already holds.
Cause: files at its path that have another hardlink (a Sonarr/Radarr import, typically), or that another torrent names, did not verify against its pieces; Hydranos will not write over them (rechecks are guarded the same way). Check: WARN path collision: …, or kind path_collision in GET /api/health/anomalies. Fix: decide which file is right; Set location… elsewhere, or remove the torrent. See: Files another torrent already holds.
Cause: adding over existing files rechecks unless the add asked for seed mode (the Add tab's Skip the hash check, the data is already on disk, the REST and shim options; watched folders, MCP and RSS magnets never do); files held by the path claim are proven first; or the last stop was not clean. Fix: let it finish; correct data is not downloaded again. See: Adding Torrents and Existing Data.
Cause: the save path is not where the files are. Single file: <save path>/<file>; multi-file: <save path>/<torrent name>/…. Fix: Set location… to the folder that holds the data (for multi-file, the parent of the torrent's folder). See: Jobs, Bulk Actions and Moving Data.
Cause: the item is shown only when the selection holds at least one hoard row; once shown, it rechecks race copies too. Fix: include a hoard row, or use the REST verify route or the shim's torrents/recheck. See: Jobs, Bulk Actions and Moving Data.
Cause: no metadata: no reachable peer through its trackers, x.pe or DHT, or the engine is off the network. After the last attempt the log says magnet given up. Fix: Retry, or add the .torrent file. See: Magnets on Adding Torrents and Existing Data.
Cause: the add was refused; the reason is in <name>.invalid.txt beside it. Fix: fix the category or its save path, rename the file back. See: Watched folders on Adding Torrents and Existing Data.
Check: the folder's Status on the Config tab. not scanned yet right after a start is normal. seen 0 while files are in the folder means Hydranos does not see them: in Docker, a network share mounted on the host after the container started leaves the container on the empty mountpoint. An error no answer from this folder for 60 s … means the share stopped answering; the other folders are still scanned. Fix: mount the share's parent with rslave propagation, or restart the container once the share is mounted; for a share that hangs, fix the mount on the host. See: Watched folders on Adding Torrents and Existing Data.
Cause: with active_downloads above 0 (hoard ships with 10), an engine downloads at most that many at once; under queueing = true, active_limit also counts seeds. A torrent you stopped stays stopped. Fix: Start what you stopped; Force download a torrent that must not wait; raise active_downloads (0 = no ceiling) or set dont_count_slow_torrents = true; both apply live. See: Queue, Share and Speed Limits.
Cause: a share limit was reached (log share limit reached: stopped, or …: removed with share_limit_action = "remove"), or, with queueing = true, active_seeds / active_limit parked the seed (queuedUP over the shim). Fix: raise or clear the share limits (engine, or Share limits… per torrent), or the queue ceilings. See: Queue, Share and Speed Limits.
Check: the feed's State (blocked by the kill switch, last error), the Workflows tab's Activity (RSS: <rule>), the rule's Preview. Causes: rule disabled or not watching the feed; article already taken (once only, refusals included); a title without episode number never matches an episode filter; Ignore later matches for; or no category with a save path and no Save path: every add is refused with no save path: …, for good. Fix: give the rule such a category; re-add a refused article with Download. See: RSS and Automatic Downloads.
After an upgrade some torrents are stopped, with a WARN starting client spoofing has been removed from Hydranos
Cause: the config still had [announce_clients] tables; matching torrents were stopped once. Fix: check each tracker accepts Hydranos, then Start them. See: Upgrading from 3.x.
Check: (1) GET /api/port-forward: listening and the listen_port each engine holds (a missing or taken port is replaced: listen_port missing or taken: using a free one); (2) the ports are forwarded, TCP and UDP, and in Docker published with the same number on both sides; (3) no automatic port forward; … forward <port> (TCP and UDP) by hand means NAT-PMP/UPnP failed (usual under Docker's bridge). Fix: forward by hand, set auto_port_forward = false, test from outside. See: Checking reachability on Networking, ports table on Installation and First Run.
Cause: not in Gluetun mode, Take the listen port from gluetun off, or the control server refuses (log gluetun port forward: cannot read the port; on 401/403, set the gluetun API key, with GET /v1/portforward allowed). Until a port is read, that engine announces nothing. Fix: pick Gluetun, tick the box, set the Gluetun API key, Apply & restart. See: With gluetun on VPN and Egress.
Cause: the Hydranos container keeps gluetun's old, dead network namespace (Docker's behaviour, not tested by the maintainer); a tunnel reconnect inside a running gluetun is not affected. Fix: restart Hydranos after gluetun: docker restart -t 150 hydranos. See: VPN and Egress.
Cause: an engine with no interface, proxy or tunnel leaves by the default route when the kill switch is disarmed, the default in Direct mode (its Network tab line says NOT covered). A pinned engine (Linux) has every socket on its interface, announces and DHT included. Fix: give the engine a way out, or set [daemon] kill_switch = true so it is blocked instead; verify from outside. See: The kill switch on VPN and Egress.
Cause: with the kill switch armed (every mode but Direct, by default) the default route is not measured, so a pinned or proxied row can only say "a leak cannot be ruled out" (known bug in 4.4). Fix: verify from outside (Verify, do not trust the UI on VPN and Egress).
Cause: kill switch armed, and the engine has no interface, proxy, tunnel or allow_direct (WireGuard: Way out on Not assigned (blocked by the kill switch); Gluetun: pinned to another interface). Log kill switch: BLOCKED, kept off the network …; /health says degraded. Fix: give it a way out, tick Direct on purpose, or disarm the kill switch, then restart (decided at startup). See: VPN and Egress.
Cause: the kill switch is armed and [daemon] egress (auto) has no way to borrow: no tunnel (WireGuard), no proxy (SOCKS5), or nothing set in Direct with kill_switch = true (kill switch on in direct mode: set [daemon] egress …); an engine:<id> that is blocked is refused too. Fix: give race a tunnel or proxy, or set External requests of the daemon to proxy, direct or engine:<id>. See: The daemon's own requests on VPN and Egress.
Cause: the card names what is missing: Linux, the NET_ADMIN capability, or the ip and wg commands. Fix: Docker: cap_add: [NET_ADMIN], plus HYDRANOS_CAP_NET_ADMIN=1 with PUID/PGID; bare metal: grant the capability to the unit; elsewhere, run the VPN system-wide. Tunnel up but no port (wireguard: no port yet; the engine starts with its announces held), no handshake, name leak: Troubleshooting on Managed WireGuard.
Cause: the engine's announces go through a SOCKS5 proxy (its own, or TYPHON_ANNOUNCE_PROXY): the tracker status says UDP trackers do not go through a SOCKS5 proxy (no UDP ASSOCIATE): they will not be announced while this proxy is active; or enable_udp_trackers = false, or the URL has no port. See: Trackers and Announces.
Cause: its interface did not exist at start (log: refusing to listen on the default route); + Add an engine refuses a down interface with no interface named <name> is up. Fix: bring the interface up before Hydranos, restart. See: VPN and Egress.
Cause: 409: the port is another engine's or cannot be bound (the old one is kept), or the engine follows gluetun or its WireGuard tunnel; 503: the engine is off the network. persisted: false: moved, but default.toml not written. See: Changing the port without a restart on Networking.
Cause: the tracker does not know the torrent (deleted, replaced), or not yet: right after an upload a race-role engine retries every 5 s for registration_retry_minutes (6 by default). Fix: if it persists, remove or replace the torrent. See: Trackers and Announces.
Other error classes (Bad passkey, Rate-limited, Tracker unreachable): see the troubleshooting table on Trackers and Announces.
Cause: a copy made by Duplicate to engine › (it starts from the stored .torrent's trackers), or a move made under 4.4.0: see After a move, tracker edits… below.
Cause: shared (another torrent, or this torrent's own copy in another engine, reads the same files), destination_taken (files already at the destination would be overwritten), hardlinks (a copy would break a hardlink; the UI asks first), space, unsafe_path, or a move already queued. See: Checks before a move is queued on Jobs, Bulk Actions and Moving Data.
Cause: a running move_data job is never interrupted (409 a running move cannot be interrupted safely; it will finish); a queued job is dropped, a running graduate job stops after the current file and is rolled back. Fix: let it finish. See: Jobs, Bulk Actions and Moving Data.
Cause: under 4.4.0, a move_data job (Set location…, a same-mode category move, workflow move files to a folder) re-added the torrent in seed mode from the stored .torrent: tracker edits, counters, caps and download order were lost, and an incomplete torrent was marked complete. Since 4.4.1 every move keeps them, but what a 4.4.0 move lost stays lost. A copy made by Duplicate to engine › always starts with the .torrent's trackers and its counters at 0. Fix: redo the edits; Recheck a torrent that was moved unfinished under 4.4.0. See: Jobs, Bulk Actions and Moving Data.
Cause: a failed or cancelled graduation is rolled back; only a failed rollback leaves the torrent in no engine. (Move to engine › never does: the target adopts first.) Fix: add the .torrent again at that folder, from Download .torrent files (.zip) or a backup. See: Jobs, Bulk Actions and Moving Data.
Cause: the tracker's Minimum seed was wrong: 0 means "delete when needed". A tracker with nothing declared is protected (moved or left in place, never deleted). Fix: declare only the Minimum seed you mean, for every tracker you race on. See: Race Drain, Graduation and Seed Obligations.
Cause: the editor saves a new workflow switched off (saving an edit keeps its state). Fix: tick Enabled in the list after the first save; Run now runs a timer workflow once, enabled or not. See: Workflows.
Cause: Edit tags ›, Force download / Stop forcing and Share limits… are not relayed to nodes ({n} not on this node); the other actions are relayed and a refusal comes back as <node>: <the node's error>. no declared node holds <label> means the row's node is no longer declared. Fix: Open the node from the Nodes tab and act in its own UI. See: Nodes and Multiple Machines.
The enrolment script stops with a container named hydranos already exists and was not made by this script
Cause: it replaces only a container it made (label io.hydranos.enrolled=true). Fix: --container <another-name>, or remove that container yourself. A name already declared is refused (409) without spending the token: rerun with --name. See: Nodes and Multiple Machines.
Cause: with PUID/PGID, the entrypoint chowns /config but never /data, and a folder Docker creates for a missing bind mount belongs to root. Check: ls -ln on the host folders behind your save paths. Fix: create them before the first start and give them to that uid:gid; on Unraid 99:100 matches user shares. If the log says hydranos: already running as uid <N>, ignoring PUID/PGID, drop Docker's --user. See: User and permissions on Docker Install.
Cause: /config is not mounted, so everything lived in the container layer. (No "temporary admin password" is ever logged.) Fix: mount a host folder at /config. See: Docker Install.
Cause: any value of HYDRANOS_LOG_STDOUT, 0 included, turns the file off and leaves only the console. Fix: remove the variable. See: Docker Install.
Cause: /config on /mnt/user/… (FUSE, treated as a network filesystem). Fix: map /config to a pool path such as /mnt/cache/appdata/hydranos. See: Unraid on Docker Install.
Cause: 4.3 started without --config used \config\default.toml on the current drive (C:\config\); with no default.toml beside hydranos.exe, 4.4 keeps using it. Fix: quit Hydranos, move C:\config\'s contents beside hydranos.exe and fix data_dir, or start with --config. See: Where the config goes on Install on Windows.
Cause: the clean stop took over 60 s (a large library's save), or the running Hydranos predates 4.4 and did not hear the request. Fix: wait until hydranos.exe leaves Task Manager (or tray › Quit Hydranos), then update again. See: Updating on Install on Windows.
Cause: on shutdown, sign-out or when its console window is closed, Windows leaves Hydranos only a few seconds to save, and a windowed program may not get the shutdown event at all (not tested on Windows). Fix: tray › Quit Hydranos first, and wait until hydranos.exe leaves Task Manager. See: Stopping cleanly on Install on Windows.
On Windows an engine stays off the network, or the daemon's requests fail with [daemon] bind_interface … cannot be applied on this platform
Cause: bind_interface is Linux-only: refused (400) by the Network tab and + Add an engine; an engine whose file still sets it starts off the network. Daemon interface is accepted, then every daemon request that does not borrow an engine's route is refused, [proxy] included (known bug in 4.4). Fix: remove the key and restart; leave Daemon interface empty; run the VPN system-wide. See: VPN on Windows on Install on Windows.
Cause: rescue mode: hydra.db did not open or failed its schema check (log: the store could not be opened: <why> -- starting in rescue mode); only a few routes are served, on your api_host and api_port. Check: curl http://127.0.0.1:8199/api/store/repair (no key) shows needed, on_network and in_wal. Fix: copy the config dir first; move the data dir to a local disk. POST /api/store/repair only applies to a WAL store on a network filesystem. See: Rescue mode on Operating Hydranos.
Cause: UI restarts stop cleanly, then exit with code 75 for the supervisor to restart: Docker without a restart policy (Unraid's Autostart sets none) or a hand start on Linux leave it stopped. The shipped systemd unit (Restart=on-failure) restarts it; Windows starts its successor itself. Fix: restart: unless-stopped (--restart=unless-stopped), or start it by hand. See: Restart from the UI on Operating Hydranos.
Cause: the supervisor killed the process during the resume flush, or the flush hit HYDRANOS_STOP_TIMEOUT; the last 300 s periodic save is then used. Check: a clean stop ends with shutdown flush complete (took_s); shutdown flush hit HYDRANOS_STOP_TIMEOUT; leaving with what is saved means the budget (default 120 s; 10s means 10 s) ran out; no line means it was killed. Fix: raise HYDRANOS_STOP_TIMEOUT above took_s, and the supervisor's limit (stop_grace_period, docker stop -t, TimeoutStopSec) 10 s above it. See: Operating Hydranos.
Cause: bench.db in the data dir has no retention (about 17,000 sample rows a day, plus as many per extra engine). The log rotates itself and takes at most about 640 MiB (5 × 128 MiB). Fix: watch bench.db's size; to keep the log smaller, lower the level with RUST_LOG. See: Monitoring and Logs.
Cause: read its problems: an engine on the network without its peer listener (port not bound, or its tunnel is down), an engine blocked by the kill switch, or an engine held by start_paused. The other engines keep seeding. See: Monitoring and Logs.
Cause: update_check_disabled = true; the GitHub request failed or took over 5 s (a failure is not kept, so it is retried on the next request; a success is kept 6 hours); or the newest release is not among the first 100 tags returned. Fix: watch the releases on github.com/Kheopsian/Hydranos. See: Operating Hydranos.
Measured references: Deployment Topologies.
Cause: memory grows with torrents and connected peers (no max_connections key = no limit), and the allocator keeps freed memory. Check: the jemalloc allocated=… resident=… line logged every 300 s on Linux. Fix: set max_connections per engine; on Linux kill -USR2 <pid> makes the allocator return unused memory. See: Monitoring and Logs, Configuration: Engines.
Cause: rechecks after an unclean stop (4 at a time by default, TYPHON_RECHECK_TORRENTS), catalogue loading, announce ramp-up. Fix: clean stops, let it settle. See: Configuration: Environment and CLI.
Check: store held long warnings; HYDRANOS_WORKER_THREADS (default min(cores, 32)). The anomaly pass runs every 5 minutes on its own; polling /api/health/anomalies only reads its last result. See: Monitoring and Logs.
Open an issue on github.com/Kheopsian/Hydranos/issues (the Logs tab's Report issue link opens one). Include:
- the version and how you run it (image tag, systemd, Windows);
- what you did, expected and got;
- the
hydranos.loglines around the problem (UTC); -
default.tomlwithout secrets (api_key,password_hash,[announce_passkeys], node keys, tracker URLs with a passkey); - for performance: the
jemalloc …andstore held longlines, torrents per engine.
URLs in announce failed (http(s) only, not udp://) and qbit add: url refused lines become <url>; other lines are not. Check before pasting.