Skip to content

Plex Watchlist Sync times out due to too many concurrent Plex Discover metadata requests #3235

Description

@ik8sqi

Description

Plex Watchlist Sync fails when Seerr running in a docker container opens too many concurrent Plex Discover metadata requests when there are many items in the watchlist (in my case > 10).

The failure happens during the watchlist metadata retrieval, before Seerr can finish processing the watchlist. The UI message in the web interface is:

[Plex.TV Metadata API]: Failed to retrieve watchlist items

After adding temporary debug logging, the actual error is an Axios/Node ETIMEDOUT while fetching individual Plex Discover metadata URLs, for ex:

/library/metadata/62d7d0c54d0067dd4d6066f6

The important part is that the exact same endpoint works when requested sequentially, but fails when many requests are fired concurrently. I reproduced this inside the Seerr container with Axios:

  • 20 parallel Axios requests: the first batch succeeds, then later requests fail with ETIMEDOUT
  • 20 sequential Axios requests to the same URL: all 20 succeed with HTTP 200

This appears related to Seerr using unbounded parallel requests for watchlist item metadata, e.g. Promise.all(...), which can create too many simultaneous outbound HTTPS connections to discover.provider.plex.tv.

Adding limits to Node's global HTTP/HTTPS socket concurrency fixed the issue on my instance - adding this to the top of the plextv.js file solved it:

"use strict";
// Local workaround: limit concurrent outbound Plex Discover connections.
// Without this, Plex Watchlist Sync uses Promise.all and can open too many
// simultaneous HTTPS connections from this Docker/VM environment.
require("https").globalAgent.maxSockets = 4;
require("http").globalAgent.maxSockets = 4;

Limiting the connections to 4 solved the issue once Seer was restarted.

Host vs container test

Seer and the other "arr" apps are installed on a Ubuntu VM that is in turn running in a Parallels virtual machine on an Intel Mac. To make sure this was not the Ubuntu VM host or general network connection, I ran the same Axios parallel test both on the Ubuntu host and inside the Seerr container.

I ran this on the Ubuntu host, outside Docker:

node - <<'NODE'
const axios = require('/tmp/node_modules/axios');

const url = 'https://discover.provider.plex.tv/library/metadata/62d7d0c54d0067dd4d6066f6';

Promise.allSettled(
  Array.from({ length: 20 }, (_, i) =>
    axios.get(url, { timeout: 15000, validateStatus: () => true })
      .then(r => ({ i, status: r.status }))
      .catch(e => ({
        i,
        code: e.code,
        causeCode: e.cause?.code,
        errors: e.cause?.errors?.map(x => ({
          code: x.code,
          address: x.address,
          port: x.port,
          message: x.message
        }))
      }))
  )
).then(results => {
  for (const r of results) console.log(JSON.stringify(r));
});
NODE

Result on the Ubuntu host: all 20 requests completed at the HTTP level with 401, which is expected because no Plex token was sent. There were no timeouts.

Example output:

{"status":"fulfilled","value":{"i":0,"status":401}}
{"status":"fulfilled","value":{"i":1,"status":401}}
...
{"status":"fulfilled","value":{"i":19,"status":401}}

Then I ran the same Axios test inside the Seerr container:

docker exec -i seerr node - <<'NODE'
const axios = require('axios');

const url = 'https://discover.provider.plex.tv/library/metadata/62d7d0c54d0067dd4d6066f6';

Promise.allSettled(
  Array.from({ length: 20 }, (_, i) =>
    axios.get(url, { timeout: 15000, validateStatus: () => true })
      .then(r => ({ i, status: r.status }))
      .catch(e => ({
        i,
        code: e.code,
        causeCode: e.cause?.code,
        errors: e.cause?.errors?.map(x => ({
          code: x.code,
          address: x.address,
          port: x.port,
          message: x.message
        }))
      }))
  )
).then(results => {
  for (const r of results) console.log(JSON.stringify(r));
});
NODE

Result inside the Seerr container: the first 10 requests completed with 200, then requests 10-19 failed with ETIMEDOUT / ENETUNREACH.

Example output:

{"status":"fulfilled","value":{"i":0,"status":200}}
{"status":"fulfilled","value":{"i":1,"status":200}}
...
{"status":"fulfilled","value":{"i":9,"status":200}}
{"status":"fulfilled","value":{"i":10,"code":"ETIMEDOUT","causeCode":"ETIMEDOUT","errors":[{"code":"ETIMEDOUT","address":"172.64.151.205","port":443,"message":"connect ETIMEDOUT 172.64.151.205:443"},{"code":"ENETUNREACH","address":"2606:4700:4405::ac40:97cd","port":443,"message":"connect ENETUNREACH 2606:4700:4405::ac40:97cd:443 - Local (:::0)"},{"code":"ETIMEDOUT","address":"104.18.36.51","port":443,"message":"connect ETIMEDOUT 104.18.36.51:443"},{"code":"ENETUNREACH","address":"2a06:98c1:310a::6812:2433","port":443,"message":"connect ENETUNREACH 2a06:98c1:310a::6812:2433:443 - Local (:::0)"}]}}
...
{"status":"fulfilled","value":{"i":19,"code":"ETIMEDOUT","causeCode":"ETIMEDOUT"}}

For comparison, I also tested sequential requests inside the Seerr container:

docker exec -i seerr node - <<'NODE'
const axios = require('axios');

const url = 'https://discover.provider.plex.tv/library/metadata/62d7d0c54d0067dd4d6066f6';

(async () => {
  for (let i = 0; i < 20; i++) {
    try {
      const r = await axios.get(url, {
        timeout: 15000,
        validateStatus: () => true
      });
      console.log(JSON.stringify({ i, status: r.status }));
    } catch (e) {
      console.log(JSON.stringify({
        i,
        code: e.code,
        causeCode: e.cause?.code,
        errors: e.cause?.errors?.map(x => ({
          code: x.code,
          address: x.address,
          port: x.port,
          message: x.message
        }))
      }));
    }
  }
})();
NODE

Result inside the Seerr container sequentially: all 20 requests completed with 200.

Example output:

{"i":0,"status":200}
{"i":1,"status":200}
...
{"i":19,"status":200}

So this does not appear to be the Ubuntu host itself failing parallel outbound HTTPS. It appears specific to the Seerr container / Docker network path when Seerr opens many concurrent Plex Discover metadata requests.

In any case, whatever the root cause, limiting Node's socket concurrency to 4 inside the Seerr container stopped the Plex Watchlist Sync failures.

Version

3.3.0

Steps to Reproduce

  1. Run Seerr in Docker with Plex Watchlist Sync enabled.

  2. Have a Plex Watchlist with enough items that Seerr performs multiple Plex Discover metadata lookups during sync.

  3. Trigger Plex Watchlist Sync manually from:

    Settings -> Jobs & Cache -> Plex Watchlist Sync

    or wait for the scheduled job to run.

  4. Watch the Seerr logs.

  5. The sync may fail during metadata retrieval with:

    [Plex.TV Metadata API]: Failed to retrieve watchlist items

  6. Add temporary debug logging around the Plex.TV Metadata API error handler to expose the underlying Axios error.

  7. Trigger Plex Watchlist Sync again.

  8. The underlying failure is a connection-level timeout while fetching individual Plex Discover metadata URLs, for example:

    /library/metadata/62d7d0c54d0067dd4d6066f6

    with errors such as:

    ETIMEDOUT

    and, for IPv6 attempts:

    ENETUNREACH

  9. Reproduce the behavior independently from inside the Seerr container by running 20 parallel Axios requests to the same Plex Discover metadata URL.

  10. Compare with 20 sequential Axios requests inside the same container. In my case, the parallel test failed after the first batch, while the sequential test completed all 20 requests successfully.

Screenshots

No response

Logs

Platform

desktop

Database

SQLite (default)

Device

any

Operating System

Ubuntu 24.04.2 LTS

Browser

any

Additional Context

No response

Search Existing Issues

  • Yes, I have searched existing issues.

Code of Conduct

  • I agree to follow Seerr's Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    confirmedThis bug has been reproduced

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions