File Descriptors (FD): What They Are, How They Work, and Why You Hit EMFILE

Search for a command to run...

No comments yet. Be the first to comment.
Mind maps are an excellent addition to an MCP ecosystem when they help users understand relationships between data, tools, and reasoning. They should complement—not replace—traditional dashboards, tab
Most AI agents today depend heavily on cloud APIs. They're fast, but every request costs money, depends on an internet connection, and sends your data to external providers. Over the weekend, I experi
How I use Fable 5 to research, build, and maintain custom Claude Code plugins, marketplaces, agents, and skills—creating reusable AI tooling that works across every project. 01 · The problem with copy

The way people search is changing. Is your site ready? For the past two decades, SEO (Search Engine Optimization) was the undisputed king of web visibility. Rank on Google's first page and you win tr
How we made 30 GB PSD uploads feel instant without expensive backend conversions. When we first built our media upload system, the architecture looked completely normal. A user uploaded a file, the b

If you’ve ever seen an error like:
EMFILE: too many open files
you’ve already met one of the most fundamental pieces of an operating system: the file descriptor (FD).
This blog explains:
what an FD is
how its lifecycle works
why your system ran out of them during image export
how memory differs from FD (second problem you hit)
and how Excel image export actually behaves internally (third problem)
A file descriptor is a small integer that the operating system gives your process when it opens a file or resource.
Think of it as a ticket number:
You ask the OS: “Open this file”
OS says: “Here’s FD = 7”
You use 7 to read/write
When done → you close it
const fs = require('fs');
const fd = fs.openSync('data.txt', 'r'); // fd = 7 (example)
const buffer = Buffer.alloc(100);
fs.readSync(fd, buffer, 0, 100, 0);
fs.closeSync(fd);
In Unix systems:
Everything is treated like a file
| Resource | Uses FD? |
|---|---|
| Disk file | ✅ |
| HTTP request | ✅ |
| Socket | ✅ |
| Stream | ✅ |
[1] Request resource
↓
[2] OS opens it
↓
[3] OS assigns FD (integer)
↓
[4] Your app uses FD
↓
[5] You close FD
↓
[6] OS frees FD
Application Operating System
----------- -----------------
open() ─────────────▶ Allocate FD (e.g., 5)
Open file/socket
read(fd=5) ◀──────────▶ Read data
write(fd=5) ◀─────────▶ Write data
close(5) ─────────────▶ Release FD
Free slot
Each process has a limit:
ulimit -n
Typical values:
1024
4096
65535 (tuned systems)
EMFILE = Too Many Open Files
It means:
❗ You opened more resources than allowed at the same time
50 concurrent downloads
Each opens:
1 HTTP socket (FD)
1 file write (FD)
👉
50 × (socket + file) = ~100 FDs
With multiple jobs:
5 jobs → ~500 FDs → EMFILE
await Promise.all(urls.map(download));
👉 Opens everything at once
for (const url of urls) {
await download(url);
}
👉 Controlled FD usage
This is where many people get confused.
| Concept | FD | Memory |
|---|---|---|
| What it is | Handle | Data |
| Managed by | OS | Your app |
| Limit | OS limit (ulimit) | RAM |
| Error | EMFILE | OOM (Out of Memory) |
const buffer = await fs.readFile('image.jpg');
open file → FD used
read file → buffer created in RAM
close file → FD released
👉 After this:
FD = ❌ gone
Buffer = ✅ still in memory
❗ Closing a file does NOT free memory
Even after fixing EMFILE:
workbook.addImage({ buffer })
👉 ExcelJS stores ALL buffers internally
So:
6000 images × 150KB ≈ 900MB RAM
👉 This leads to memory pressure, not FD issue
FD = number of doors open 🚪
Memory = stuff inside the room 📦
Closing doors doesn’t remove the stuff.
You noticed:
After ~3000 rows → images overlap at top
Excel calculates image positions using:
Row height → converted to EMU
1pt = 12,700 EMU
Each image Y position = sum of all previous row heights
Excel internally uses:
32-bit signed integer
Max = 2,147,483,647
If:
row height = 50pt
→ 50 × 12700 = 635,000 EMU per row
Then:
2,147,483,647 / 635,000 ≈ 3,382 rows
Value overflows → becomes negative
→ Excel places image at wrong position (top)
→ all images overlap
Correct:
Row 1 → Y = 0
Row 2 → Y = 635k
Row 3000 → Y = valid
After overflow:
Row 3500 → Y = negative ❗
→ jumps to top
→ overlap
You reduced:
row height = 16pt
👉 avoids overflow BUT:
image still 50px
row smaller than image
UI breaks
limit concurrency
avoid massive Promise.all
compress images
reduce unique images
limit concurrent exports
👉 Split sheets
Sheet 1 → 0–3000 rows
Sheet 2 → 3001–6000
reduce image size
or fallback to URLs
Problem 1 → FD (too many things open at once)
Problem 2 → Memory (too much data kept)
Problem 3 → Excel limit (internal integer overflow)
FD issues are about “how many things are open at once”, memory issues are about “how much data you keep”, and Excel issues are about “format limitations you cannot bypass.”