fix(sdk): select stack-trace frames by SDK boundary instead of fixed depth - #1599
Conversation
…depth Replace STACK_TRACE_DEPTH fixed-depth walking with boundary-based frame selection: the caller's frame is the first one whose file lies outside the SDK package. Frame parsing in the JS SDK is delegated to error-stack-parser-es (ESM-only, inlined via tsdown noExternal since the engines range includes Node versions without require(esm)). The Python SDK walks f_back until co_filename leaves the e2b package root. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 4e3aa98 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
PR SummaryMedium Risk Overview JS: Python: Same boundary walk via Tests add Reviewed by Cursor Bugbot for commit 4e3aa98. Bugbot is set up for automated code reviews on this repo. Configure here. |
Package ArtifactsBuilt from d823efc. Download artifacts from this workflow run. JS SDK ( npm install ./e2b-2.35.4-boundary-based-stack-frames.0.tgzCLI ( npm install ./e2b-cli-2.15.1-boundary-based-stack-frames.0.tgzPython SDK ( pip install ./e2b-2.34.0+boundary.based.stack.frames-py3-none-any.whl |
Boundary-based capture resolves through SDK-internal delegation to the user's call site, so collectStackTrace inside runCmd/copy/parseDockerfile already records the right frame. The disable/enable + collect-after wrapper and the override context (and their Python equivalents) are redundant — remove them and call the delegated methods directly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Errors carrying a template-definition stack trace previously overwrote error.stack with raw frame lines, so reporters printing error.stack lost the failure message and the SDK-internal throw site. withStackTrace() now synthesizes `Name: message\n<frames>` lazily (subclass names set after super() still appear) and preserves the natural stack on error.cause. The copyItems re-throw wrapper is removed in both SDKs — copy()'s boundary capture already points validation errors at the copyItems call site. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Plain `error.cause = x` creates an enumerable own property, so every
error decorated by withStackTrace() leaked a "cause" key into
Object.keys() and JSON.stringify() output. Native `new Error(msg,
{cause})` installs cause non-enumerable per spec — do the same via
Object.defineProperty.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
## Description Adds `--project template` to `test:bun` so the Bun CI leg runs the template suite, matching the Deno leg (#1595). No code changes are needed: the template suite previously failed under Bun because Bun's JavaScriptCore elides tail-call frames and the fixed-depth stack walk attributed build errors one frame past the user's call site (the workaround attempt in #1596 was closed in favor of #1599). With #1599's boundary-based frame selection (now merged), the suite passes under Bun as-is. The CI workflow already passes `E2B_API_KEY`/`E2B_DOMAIN` to the Bun leg, and the matrix comment (updated in #1595) already covers Bun re-running API-backed suites, so `package.json` is the only change. ## Testing Full `test:bun` (unit + connectionConfig + template) green locally on Bun 1.3.14 against the real API: 530 passed, 35 skipped, 0 failed — including all 34 stack-trace/caller-directory tests that pin exact user call-site line/columns, the frames Bun used to elide. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Description
Template build stack traces were captured by walking a fixed number of frames (
STACK_TRACE_DEPTHplus±1arithmetic at ~15 call sites), which broke whenever the frame count betweennew Error()and user code shifted — TS class-field initializer frames (#1539) and Bun's tail-call frame elision were both this bug. This PR makes two related changes:error-stack-parser-es(ESM-only, so it's a devDependency inlined into both dist formats via tsdownnoExternal— the engines range includes Node versions withoutrequire(esm)); the Python SDK equivalently walksf_backuntilco_filenameleaves thee2bpackage root, in the shared builder used by both sync and async. If no user frame is identifiable (e.g. the SDK is bundled into the caller's own file), capture degrades to no trace rather than a wrong frame.remove()→runCmd(),fromDockerfile()→ parser) to the user's call site on its own, the suppress/override collection machinery (runInNewStackTraceContext,runInStackTraceOverrideContext, the enabled/override flags, and their Python equivalents) became redundant and is removed — superseding the approach in feat(js-sdk): run the template test suite on Bun #1596.Error
.stacksynthesis (keeping theName: messageheader and the throw site oncause) was prototyped here and backed out — it will come as a follow-up PR.Usage
No API changes — build errors now point at the user's call site regardless of runtime or transpiler:
Testing
unit+templatevitest projects green against the real API (incl. 27 per-method stacktrace tests pinning exact call-site line/columns,bunInstallnow covered); edge-compat bundle test and CLI build verified; built CJS/ESM dists smoke-tested withrequire()/import().test_stacktrace.pysuites,bun_installnow covered);ruffandtyclean.🤖 Generated with Claude Code