Skip to content
Troubleshooting

Troubleshooting

Start with these two, in this order — they answer most questions without guessing:

subtrace config show    # the configuration actually in effect, secrets masked
subtrace status         # what the database believes, and today's quota use

Add --log-level debug to any command for the reasoning behind a skip.

“cannot write to library root”

error: cannot write to library root /media/Movies: permission denied
subtrace writes subtitle files next to the videos, so the process needs write access there.

fetch probes every root before doing any work, so this fails immediately rather than thousands of files in. Causes, most common first:

  1. The media mount is read-only. Media servers usually mount libraries :ro; subtrace cannot. Remove the :ro.
  2. PUID/PGID do not match the files’ owner. Check with ls -ln /mnt/media/Movies on the host and compare the numeric uid/gid.
  3. The directory genuinely denies writes to that user. chmod/chown on the host.

--dry-run skips the probe, which is a quick way to confirm the rest of the setup is fine while you sort permissions out.

Everything comes back not_found

Look at what is being asked for:

subtrace fetch --limit 1 --log-level debug

If the folder names carry no {tmdb-…} / {imdb-…} / {tvdb-…} id, subtrace falls back to a title-and-year search, and misses are expected. Renaming to the Plex/TRaSH convention is the real fix — Radarr and Sonarr do it automatically. See Naming and matching.

Also worth checking:

  • The language exists for that title. A less common languages entry will legitimately be missing for a lot of the catalogue.
  • Only one provider is actually configured. subtrace status lists the enabled providers; one missing an API key is skipped silently.

Nothing is downloading, but nothing is failing either

Almost always the daily cap:

downloads today
  opensubtitles   100 / 100
  subdl           100 / 100

Once every provider is parked, remaining items are left pending — deliberately not marked failed, so they are not charged an attempt. The counter is keyed by UTC date, so it resets at midnight UTC, not at your local midnight.

The other possibility is that the batch is empty because everything eligible is in backoff: not_found items wait run.retry_after_hours (default 168h). Force a retry with subtrace fetch --force.

Subtitles land but Plex/Jellyfin does not show them

  • Ownership. Written files are chown’d to PUID:PGID only when subtrace is running as root. Outside the container, files are owned by whoever ran it. ls -l next to the video and compare with the media server’s user.
  • Naming. subtitles.naming must produce something your server recognizes. The default {basename}.{lang}.srt is what Plex auto-detects.
  • Scan timing. Without the Plex integration, the server picks them up on its own next scan.

The Plex refresh does nothing

Debug logs show:

plex refresh matched no library section (path mapping differs?)

Sections are matched by filesystem path. A container that sees /media/Movies while Plex sees /data/movies will never match. Mount the library at the same path in both.

The scan count looks wrong

Way too high — usually double-counting from a NAS metadata directory. @eaDir is in ignore_dirs by default; if you overrode that list, put it back. Also check min_file_size_mb (default 50): sample files and clips inflate counts when it is set to 0.

Way too low — check that scan.video_extensions covers your container formats, and that an over-broad ignore pattern is not eating real files. Remember * does not cross /, so */Extras/* matches nothing while **/Extras/** works. See Ignore patterns.

Files that already have subtitles are counted as missing — subtrace looks for sidecars only. Embedded tracks inside the container are not examined.

“not a valid subtitle file”

not a valid subtitle file: provider returned an HTML page
not a valid subtitle file: no subtitle timecodes found
not a valid subtitle file: empty response

This is working as intended: the download was rejected before it could reach the disk. subtrace tries the next candidate. Seeing it constantly for one provider usually means a credential problem — an expired login often comes back as an HTML page rather than a proper error.

“no config file found”

error: no config file found (looked in: subtrace.toml, /home/you/.config/subtrace/subtrace.toml, /config/subtrace.toml)

Write one with:  subtrace config init > subtrace.toml

In a container this means /config is not mounted, or the file inside it is not named subtrace.toml. Point at it explicitly with SUBTRACE_CONFIG if you keep it elsewhere.

Database questions

run.db_path defaults to /config/subtrace.db when /config exists, and ~/.local/share/subtrace/subtrace.db otherwise. It is a plain SQLite file:

sqlite3 "$(subtrace config show | awk '/^database/{print $2}')" \
  "select status, count(*) from items group by status;"

Deleting it loses history only — the next scan rebuilds everything from disk, and files that already have sidecars go straight to have. The one thing you lose is today’s quota counter, so subtrace may exceed the provider’s real cap for that day.

Reporting a bug

Include your folder layout (one representative path) and a subtrace config show dump — secrets are already masked. Issues: https://github.com/alexraskin/subtrace/issues.