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

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)
π§ What is a File Descriptor (FD)?
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
π§Ύ Example
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);
π¦ What counts as a file?
In Unix systems:
Everything is treated like a file
| Resource | Uses FD? |
|---|---|
| Disk file | β |
| HTTP request | β |
| Socket | β |
| Stream | β |
π FD Lifecycle (Step-by-Step)
[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
π Diagram
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
π’ Why FD Limits Exist
Each process has a limit:
ulimit -n
Typical values:
1024
4096
65535 (tuned systems)
π₯ What is EMFILE?
EMFILE = Too Many Open Files
It means:
β You opened more resources than allowed at the same time
𧨠Real Example (Your Case)
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
β Bad Pattern
await Promise.all(urls.map(download));
π Opens everything at once
β Good Pattern
for (const url of urls) {
await download(url);
}
π Controlled FD usage
π§ NEW TOPIC 1: FD vs Memory (Critical Difference)
This is where many people get confused.
π Comparison
| Concept | FD | Memory |
|---|---|---|
| What it is | Handle | Data |
| Managed by | OS | Your app |
| Limit | OS limit (ulimit) | RAM |
| Error | EMFILE | OOM (Out of Memory) |
π Example
const buffer = await fs.readFile('image.jpg');
What happens:
open file β FD used
read file β buffer created in RAM
close file β FD released
π After this:
FD = β gone
Buffer = β still in memory
π₯ Key Insight
β Closing a file does NOT free memory
𧨠Your second problem (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
π§ Simple analogy
FD = number of doors open πͺ
Memory = stuff inside the room π¦
Closing doors doesnβt remove the stuff.
π§ NEW TOPIC 2: Excel Image Rendering Limitation (Your 3rd Issue)
You noticed:
After ~3000 rows β images overlap at top
π Root cause
Excel calculates image positions using:
Row height β converted to EMU
1pt = 12,700 EMU
Each image Y position = sum of all previous row heights
β οΈ Limitation
Excel internally uses:
32-bit signed integer
Max = 2,147,483,647
π Calculation
If:
row height = 50pt
β 50 Γ 12700 = 635,000 EMU per row
Then:
2,147,483,647 / 635,000 β 3,382 rows
π₯ What happens after that?
Value overflows β becomes negative
β Excel places image at wrong position (top)
β all images overlap
π Visual
Correct:
Row 1 β Y = 0
Row 2 β Y = 635k
Row 3000 β Y = valid
After overflow:
Row 3500 β Y = negative β
β jumps to top
β overlap
β Why your βrow height fixβ felt bad
You reduced:
row height = 16pt
π avoids overflow BUT:
image still 50px
row smaller than image
UI breaks
π Proper Solutions (Summary)
β For FD issue
limit concurrency
avoid massive
Promise.all
β For Memory issue
compress images
reduce unique images
limit concurrent exports
β For Excel overlap issue
Best:
π Split sheets
Sheet 1 β 0β3000 rows
Sheet 2 β 3001β6000
Alternative:
reduce image size
or fallback to URLs
π§ Final Mental Model
Problem 1 β FD (too many things open at once)
Problem 2 β Memory (too much data kept)
Problem 3 β Excel limit (internal integer overflow)
π¬ One-line takeaway
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.β
Comments
Join the discussionNo comments yet. Be the first to comment.
