You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug] Desktop (Windows): per-record storage loads every record file at once → EMFILE during Host startup (14k session_projcache files)
#9609
On startup, @deepseek-ai/dsh-storage-json reads every document of a per-record unit in one unbounded Promise.all. With a large ~/.dsh/storages/session_projcache/sessions/ directory (14,136 files in my case) the Host process runs out of file handles within ~2.6 s of starting. The EMFILE storm then breaks unrelated plugins that need a handle at the same moment — in my case the required connection plugin, which left behind an empty ~/.dsh/.credentials.yaml.lock (see #7924) and made every later start fail.
Environment
DeepSeek Harness Desktop 0.2.0-rc.2 (nightly channel), Electron 44.0.0, Node 24.18.1
Windows 11 Home (build 26300), x64
~/.dsh/sessions: 13,171 workspace folders (13,122 created by automated benchmark runs in %TEMP%)
The app started with no visible window (see the separate report about the hidden window).
Running the Host entry point by hand with a small fs instrumentation preload (--require probe.cjs) showed this, ~2.6 s after start:
[probe 2.6s] EMFILE on C:\Users\<user>\.dsh\storages\session_projcache\sessions\session-907ca432-….json
[probe 2.6s] EMFILE on C:\Users\<user>\.dsh\storages\session_projcache\sessions\session-9074191d-….json
… (hundreds more, all in session_projcache/sessions)
The startup then failed with:
StartupError: dsh: startup failed: 1 required plugin did not activate
Failed plugins:
connection (required)
Package: @deepseek-ai/dsh-client-connection
Error: EMFILE: too many open files, open 'C:\Users\<user>\.dsh\.credentials.yaml.lock'
at async withFileLock (…/dsh-atomic-write/lib/index.js:195:4)
Plugins waiting for services:
session-log-download connection
open-in-app connection
session-controller fileUploads
file-upload connection
ui-deliverables connection, sessionController
bot sessionController, connection
On other runs the same startup simply stalled for more than 90 s with no fatal message at all.
There's no limit on concurrency. N files means N simultaneous open() calls.
An EMFILE on a record is silently treated as "record absent", so the storage layer never notices. Meanwhile the handle exhaustion hits other modules (credentials lock, plugin imports, …) that do treat it as fatal.
Workaround
Quit the app. Move ~/.dsh/storages/session_projcache aside. Then copy back only the session-<id>.json files whose session still exists under ~/.dsh/sessions. Don't leave the cache empty: an empty cache hides all sessions, see the separate report. Also delete the empty ~/.dsh/.credentials.yaml.lock if one is present.
Suggested fixes
Bound the concurrency of loadTableRecords (e.g. a small worker pool of 32–64, or sequential opendir iteration). Reading 14k small files sequentially is still fast; doing it all at once isn't safe.
Don't swallow EMFILE/ENFILE in readRecord. Retry with back-off, or at least log it. A silent "absent" hides the real problem and turns it into a crash somewhere else.
Load lazily. The projection cache only needs a record when a session is listed or opened, so it doesn't have to read every record into memory at Service.init.
Prune the cache. Drop records whose session folder no longer exists, and cap or expire old entries, so the directory doesn't grow forever.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Summary
On startup,
@deepseek-ai/dsh-storage-jsonreads every document of aper-recordunit in one unboundedPromise.all. With a large~/.dsh/storages/session_projcache/sessions/directory (14,136 files in my case) the Host process runs out of file handles within ~2.6 s of starting. The EMFILE storm then breaks unrelated plugins that need a handle at the same moment — in my case the requiredconnectionplugin, which left behind an empty~/.dsh/.credentials.yaml.lock(see #7924) and made every later start fail.Environment
~/.dsh/sessions: 13,171 workspace folders (13,122 created by automated benchmark runs in%TEMP%)~/.dsh/storages/session_projcache/sessions: 14,136session-*.jsonfilesWhat I saw
fsinstrumentation preload (--require probe.cjs) showed this, ~2.6 s after start:On other runs the same startup simply stalled for more than 90 s with no fatal message at all.
Root cause (from the shipped bundle)
dsh/node_modules/@deepseek-ai/dsh-storage-json/lib/index.js,loadTableRecords:and
readRecordswallows every error:So:
open()calls.EMFILEon a record is silently treated as "record absent", so the storage layer never notices. Meanwhile the handle exhaustion hits other modules (credentials lock, plugin imports, …) that do treat it as fatal.Workaround
Quit the app. Move
~/.dsh/storages/session_projcacheaside. Then copy back only thesession-<id>.jsonfiles whose session still exists under~/.dsh/sessions. Don't leave the cache empty: an empty cache hides all sessions, see the separate report. Also delete the empty~/.dsh/.credentials.yaml.lockif one is present.Suggested fixes
loadTableRecords(e.g. a small worker pool of 32–64, or sequentialopendiriteration). Reading 14k small files sequentially is still fast; doing it all at once isn't safe.EMFILE/ENFILEinreadRecord. Retry with back-off, or at least log it. A silent "absent" hides the real problem and turns it into a crash somewhere else.Service.init.All reactions