← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

File Descriptors & ulimit

Linux PHP 5.0+ Intermediate
debt(d7/e5/b5/t7)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The tools listed (ulimit, lsof, datadog, prometheus-node-exporter) can catch FD exhaustion, but only if monitoring is explicitly set up — a common_mistake noted is 'No monitoring of FD usage — exhaustion typically happens gradually, not suddenly.' The error typically surfaces only under load in production, not during development or standard CI.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix involves changes at multiple layers: sysctl.conf (kernel), systemd unit files (LimitNOFILE), and application-level code changes to close file handles properly. This is not a single-line patch but also not a full architectural rework — it spans OS configuration and potentially multiple long-running scripts.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). The concept applies to both web and CLI contexts in PHP, meaning any long-running PHP process (FPM workers, queue workers) must account for FD management. It is not purely localised (b3) because it affects multiple runtime contexts and requires ongoing operational discipline, but it does not reshape the entire system architecture (b7).

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap (contradicts how a similar concept works elsewhere)' (t7). The misconception field states that 'too many open files' errors are assumed to mean legitimately high concurrency, when they are commonly caused by FD leaks — not closing handles. Additionally, a documented gotcha is that systemd ignores /etc/security/limits.conf, so developers who correctly set ulimit in the OS profile are surprised it has no effect on services — this contradicts the expected behaviour of OS-level limits.

About DEBT scoring →

Also Known As

file descriptor ulimit too many open files FD limit

TL;DR

File descriptors are integer handles for open files, sockets, and pipes — each process has a limit (ulimit -n), and exhausting them causes 'too many open files' errors.

Explanation

Every open file, socket, pipe, or device is a file descriptor (FD). FD 0 = stdin, 1 = stdout, 2 = stderr. The soft limit (ulimit -n) is the default per-process maximum (typically 1024); the hard limit is the kernel maximum. Symptoms of FD exhaustion: 'Too many open files' errors, inability to accept new connections, failed file opens. For PHP web servers and queue workers: increase limits in /etc/security/limits.conf (system) or in the systemd service file (LimitNOFILE). Monitoring: /proc/PID/fd shows open FDs for a process; lsof -p PID lists them with paths.

Common Misconception

Too many open files errors mean too many files are open simultaneously — often caused by FD leaks (not closing files/sockets after use) rather than legitimately high concurrency.

Why It Matters

A PHP queue worker that opens database connections without closing them properly exhausts its FD limit and crashes — understanding FD limits is essential for debugging long-running PHP processes.

Common Mistakes

  • Not closing file handles in PHP after use — FDs accumulate over time in long-running scripts.
  • Low ulimit for high-concurrency services — Nginx default (1024) is insufficient for busy servers.
  • Not setting LimitNOFILE in systemd service files — systemd ignores /etc/security/limits.conf for services.
  • No monitoring of FD usage — exhaustion typically happens gradually, not suddenly.

Code Examples

✗ Vulnerable
// PHP FD leak — file handle not closed:
function processLogs(array $paths): void {
    foreach ($paths as $path) {
        $handle = fopen($path, 'r'); // Opens FD
        while (!feof($handle)) processLine(fgets($handle));
        // Missing: fclose($handle) — FD leaked!
    }
    // 1000 log files = 1000 leaked FDs — ulimit hit
}
✓ Fixed
// Close handles explicitly:
function processLogs(array $paths): void {
    foreach ($paths as $path) {
        $handle = fopen($path, 'r');
        try {
            while (!feof($handle)) processLine(fgets($handle));
        } finally {
            fclose($handle); // Always closed
        }
    }
}

# Increase FD limit for PHP-FPM in systemd:
# /etc/systemd/system/php8.3-fpm.service.d/override.conf:
[Service]
LimitNOFILE=65536

# Check current FD usage:
lsof -p $(pgrep php-fpm | head -1) | wc -l

Added 16 Mar 2026
Edited 5 Apr 2026
Views 45
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 1 ping T 0 pings F 2 pings S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Amazonbot 7 Ahrefs 5 Perplexity 4 Scrapy 4 Unknown AI 2 Google 2 ChatGPT 2 Majestic 1 Claude 1 Meta AI 1 Sogou 1
crawler 27 crawler_json 3
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Medium
⚡ Quick Fix
Check ulimit -n on your PHP-FPM server — the default 1024 can be exhausted under load; set fs.file-max in /etc/sysctl.conf and LimitNOFILE in systemd service files
📦 Applies To
PHP 5.0+ any web cli
🔗 Prerequisites
🔍 Detection Hints
Too many open files error in PHP; PHP-FPM workers failing to open sockets; connection refused under high load due to FD exhaustion
Auto-detectable: ✓ Yes ulimit lsof datadog prometheus-node-exporter
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Medium Context: File
CWE-400 CWE-772


✓ schema.org compliant