Problem
_run_lambda (src/zagg/runner.py:452) fans out via ThreadPoolExecutor(max_workers=max_workers), where each worker holds an open socket to the Lambda endpoint for a synchronous invoke. The lambda-backend default is max_workers=1700 (and the CLI accepts arbitrary values).
On stock macOS / many Linux login shells the open-file limit (ulimit -n) defaults to 256. Once concurrent workers exceed it, invocations fail with:
[Errno 24] Too many open files
Could not connect to the endpoint URL: ".../functions/process-shard/invocations"
This is a client-side failure — AWS never receives those cells, so they're dropped from the output while the run still "completes." In practice --max-workers 900 lost ~430/1330 cells; even --max-workers 500 silently caps at ~246 concurrent (≈ the 256 FD limit) if ulimit isn't raised.
Why it's a footgun
- The default (
1700) is far above any common ulimit -n, so the default invocation can fail on a fresh machine.
- The error reads like an AWS/network fault, not a local FD limit.
- Wall-clock is gated by the slowest single cell anyway, so high concurrency has little upside — the risky default buys nothing.
Proposed fixes (some combination)
- Saner default — clamp default
max_workers to something safe on a 256 FD limit (e.g. 128–200), or derive from resource.getrlimit(RLIMIT_NOFILE) minus headroom.
- Bounded connection reuse — share one boto3 client with
botocore.config.Config(max_pool_connections=...) across threads so FD use is bounded regardless of worker count.
- Pre-flight — read
ulimit -n at startup; if max_workers exceeds it, raise the soft limit via resource.setrlimit (up to hard) or clamp + warn clearly.
- Clear error — catch
OSError: [Errno 24] and surface "raise ulimit -n or lower --max-workers" instead of the raw connection error.
Workaround (documented)
ulimit -n 8192 before running; keep --max-workers ≤ min(ulimit -n − headroom, account concurrency). See docs/deployment/lambda.md → "Concurrency, workers, and file descriptors".
Problem
_run_lambda(src/zagg/runner.py:452) fans out viaThreadPoolExecutor(max_workers=max_workers), where each worker holds an open socket to the Lambda endpoint for a synchronousinvoke. The lambda-backend default ismax_workers=1700(and the CLI accepts arbitrary values).On stock macOS / many Linux login shells the open-file limit (
ulimit -n) defaults to 256. Once concurrent workers exceed it, invocations fail with:This is a client-side failure — AWS never receives those cells, so they're dropped from the output while the run still "completes." In practice
--max-workers 900lost ~430/1330 cells; even--max-workers 500silently caps at ~246 concurrent (≈ the 256 FD limit) ifulimitisn't raised.Why it's a footgun
1700) is far above any commonulimit -n, so the default invocation can fail on a fresh machine.Proposed fixes (some combination)
max_workersto something safe on a 256 FD limit (e.g. 128–200), or derive fromresource.getrlimit(RLIMIT_NOFILE)minus headroom.botocore.config.Config(max_pool_connections=...)across threads so FD use is bounded regardless of worker count.ulimit -nat startup; ifmax_workersexceeds it, raise the soft limit viaresource.setrlimit(up to hard) or clamp + warn clearly.OSError: [Errno 24]and surface "raise ulimit -n or lower --max-workers" instead of the raw connection error.Workaround (documented)
ulimit -n 8192before running; keep--max-workers ≤ min(ulimit -n − headroom, account concurrency). Seedocs/deployment/lambda.md→ "Concurrency, workers, and file descriptors".