🤖 fix: prevent jsdom ENOENT from crashing Docker streaming pipeline#3025
Open
anas-domesticus wants to merge 2 commits intocoder:mainfrom
Open
🤖 fix: prevent jsdom ENOENT from crashing Docker streaming pipeline#3025anas-domesticus wants to merge 2 commits intocoder:mainfrom
anas-domesticus wants to merge 2 commits intocoder:mainfrom
Conversation
jsdom has filesystem dependencies (browser/default-stylesheet.css) that break when bundled with esbuild for the Docker runtime — __dirname resolves to the bundle location instead of jsdom's package directory. This caused ENOENT crashes during streamMessage tool assembly, followed by cascading "p is not a function" errors on every retry attempt as jsdom's corrupted module cache returned undefined exports. Wrap the dynamic import in a try/catch so the rest of the toolset still works. Anthropic models already replace web_fetch with a provider-native tool, so the impact is minimal. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
jsdom reads browser/default-stylesheet.css from disk via a __dirname-relative path. When esbuild bundles jsdom into server-bundle.js, __dirname resolves to the bundle directory instead of jsdom's package directory, causing ENOENT in the Docker runtime. Externalize jsdom from the esbuild server bundle (like ssh2 and agent-browser) so it keeps its original filesystem layout. Add a dependency-tracing step in the Dockerfile builder stage and copy the full transitive tree into the runtime image. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fix
web_fetchtool crashing the entire streaming pipeline in Docker deployments. jsdom's filesystem dependency onbrowser/default-stylesheet.cssbreaks when bundled with esbuild, causing ENOENT on first message send and cascadingTypeError: p is not a functionon every subsequent retry.Background
Production logs from the web UI showed two interleaved errors when sending any message:
ENOENT: no such file or directory, open '/app/browser/default-stylesheet.css'— jsdom reads this CSS file from disk via a__dirname-relative path. After esbuild bundles jsdom intoserver-bundle.js,__dirnameresolves to the bundle directory instead of jsdom's original package location, so the path is wrong.TypeError: p is not a function— after the initial ENOENT, jsdom's module is left in a partially-initialized state in Node's module cache. Every retry and fresh send re-enters the same corrupted module, hitting an undefined function (minified asp). The auto-retry manager retries every ~1 second indefinitely, flooding the logs.The root cause is that
getToolsForModel()dynamically importsweb_fetch.ts(which imports jsdom) on everystreamMessagecall. When jsdom fails to load, the entire tool assembly throws, preventing ALL tools from being registered — not justweb_fetch.Implementation
Two layered fixes:
Graceful fallback (
tools.ts): Wrap the jsdom dynamic import in try/catch soweb_fetchis omitted from the toolset instead of crashing. This is defense-in-depth — Anthropic models already replaceweb_fetchwith a provider-native tool (webFetch_20250910), so losing it is low-impact.Externalize jsdom (
Makefile+Dockerfile): Add--external:jsdomtoESBUILD_SERVER_FLAGSso jsdom keeps its original filesystem layout at runtime. Trace jsdom's full transitive dependency tree in the builder stage and copy it into the runtime image.Risks
require.resolvein the builder — if a transitive dep uses conditional/optional requires that aren't independencies, they'll be missed. The graceful fallback (fix 1) covers this as a safety net.web_fetchtool.Generated with
mux