Skip to content

fix: support frozen intrinsics when adjusting Error.stackTraceLimit#2444

Merged
tim-smart merged 1 commit into
Effect-TS:mainfrom
bweis:fix/frozen-intrinsics-stack-trace-limit
Jun 19, 2026
Merged

fix: support frozen intrinsics when adjusting Error.stackTraceLimit#2444
tim-smart merged 1 commit into
Effect-TS:mainfrom
bweis:fix/frozen-intrinsics-stack-trace-limit

Conversation

@bweis

@bweis bweis commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Ports Effect-TS/effect#6279 to effect-smol.

Type

  • Bug Fix

Description

In hardened/deterministic JavaScript environments (SES "frozen intrinsics", Temporal-style sandboxes), Error is frozen and Error.stackTraceLimit is read-only. Effect mutates stackTraceLimit in several internal spots to capture short or empty stack traces cheaply, using the pattern:

const limit = Error.stackTraceLimit
Error.stackTraceLimit = 2
const err = new Error()
Error.stackTraceLimit = limit

In these environments the assignments throw, breaking Effect entirely.

This PR adds packages/effect/src/internal/stackTraceLimit.ts, which checks writability once at module load (mirroring Node's internal guard) and exposes getStackTraceLimit() / setStackTraceLimit() helpers where set is a silent no-op when the property can't be modified. All raw mutations are replaced with these guarded calls, with new Error() kept inline at each call site so the captured stack trace still points at the real caller rather than the helper.

Call sites updated: Context.ts, Layer.ts, LayerMap.ts, internal/effect.ts (cause pretty-errors, Effect.fn), internal/tracer.ts, unstable/httpapi/HttpApiMiddleware.ts, unstable/rpc/RpcMiddleware.ts.

Notes for review (vs. the upstream effect PR)

The effect-smol layout differs from Effect-TS/effect, so this is a port rather than a cherry-pick:

  • Internals are consolidated (internal/effect.ts, public Context.ts/Layer.ts/LayerMap.ts) rather than split across cause/core-effect/runtime/layer/context; there is no Micro.ts.
  • The new helper reuses the existing ErrorWithStackTraceLimit interface and .ts import extensions.
  • unsafeSecureJsonParse (unstable/ai/Tool.ts) imports the internal helper directly instead of duplicating the guard, because ai lives in the same package here (unlike @effect/ai upstream).

Behavior in normal (writable) environments is unchanged. A changeset and a dedicated test (packages/effect/test/StackTraceLimit.test.ts, covering both the writable and frozen paths) are included; typecheck and lint pass and the affected suites (Cause, Tracer, Context, LayerMap, Effect) are green.

Note

The original change was stood up by @arlyon. This description and PR were aided via Claude Code.

In hardened/deterministic JavaScript environments (SES "frozen intrinsics",
Temporal-style sandboxes), `Error` is frozen and `Error.stackTraceLimit` is
read-only. Effect mutates `stackTraceLimit` in several internal spots to
capture short/empty stack traces cheaply; under frozen intrinsics those
assignments throw, breaking Effect entirely.

Add an internal `internal/stackTraceLimit.ts` helper (mirroring Node's own
guard) that detects writability once at module load and degrades `set` to a
silent no-op when the property can't be modified. Replace the raw mutations
across Context.ts, Layer.ts, LayerMap.ts, internal/effect.ts, internal/tracer.ts,
HttpApiMiddleware.ts and RpcMiddleware.ts with guarded get/set calls, keeping
`new Error()` inline at each call site so captured stack traces still point at
the real caller.

`unsafeSecureJsonParse` in unstable/ai/Tool.ts imports the same internal helper
directly (it lives in the same package here, unlike `@effect/ai` upstream).

Ports Effect-TS/effect#6279 to effect-smol. Original change stood up by @arlyon.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Jun 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 3d7eaf6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 27 packages
Name Type
effect Patch
@effect/opentelemetry Patch
@effect/platform-browser Patch
@effect/platform-bun Patch
@effect/platform-node-shared Patch
@effect/platform-node Patch
@effect/vitest Patch
@effect/ai-anthropic Patch
@effect/ai-openai-compat Patch
@effect/ai-openai Patch
@effect/ai-openrouter Patch
@effect/atom-react Patch
@effect/atom-solid Patch
@effect/atom-vue Patch
@effect/sql-clickhouse Patch
@effect/sql-d1 Patch
@effect/sql-libsql Patch
@effect/sql-mssql Patch
@effect/sql-mysql2 Patch
@effect/sql-pg Patch
@effect/sql-pglite Patch
@effect/sql-sqlite-bun Patch
@effect/sql-sqlite-do Patch
@effect/sql-sqlite-node Patch
@effect/sql-sqlite-react-native Patch
@effect/sql-sqlite-wasm Patch
@effect/openapi-generator Patch

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

@bweis

bweis commented Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

effect-smol equivalent of Effect-TS/effect#6279

@tim-smart tim-smart enabled auto-merge (squash) June 19, 2026 21:27
@tim-smart tim-smart merged commit c1dfd60 into Effect-TS:main Jun 19, 2026
14 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

Bundle Size Analysis

File Name Current Size Previous Size Difference
basic.ts 6.58 KB 6.47 KB +0.11 KB (+1.64%)
batching.ts 9.09 KB 8.98 KB +0.10 KB (+1.15%)
brand.ts 6.14 KB 6.14 KB 0.00 KB (0.00%)
cache.ts 9.79 KB 9.70 KB +0.10 KB (+1.03%)
config.ts 18.80 KB 18.69 KB +0.11 KB (+0.60%)
differ.ts 16.81 KB 16.73 KB +0.08 KB (+0.49%)
http-client.ts 20.34 KB 20.23 KB +0.11 KB (+0.52%)
logger.ts 10.12 KB 10.00 KB +0.12 KB (+1.17%)
metric.ts 8.42 KB 8.32 KB +0.10 KB (+1.17%)
optic.ts 7.35 KB 7.35 KB 0.00 KB (0.00%)
pubsub.ts 13.89 KB 13.81 KB +0.08 KB (+0.60%)
queue.ts 10.98 KB 10.89 KB +0.09 KB (+0.81%)
schedule.ts 10.19 KB 10.08 KB +0.11 KB (+1.06%)
schema-fromJsonSchemaDocument.ts 3.49 KB 3.49 KB 0.00 KB (0.00%)
schema-representation-roundtrip.ts 26.81 KB 26.70 KB +0.10 KB (+0.39%)
schema-string-transformation.ts 12.48 KB 12.39 KB +0.10 KB (+0.77%)
schema-string.ts 10.18 KB 10.09 KB +0.09 KB (+0.89%)
schema-template-literal.ts 14.05 KB 13.96 KB +0.09 KB (+0.65%)
schema-toArbitraryLazy.ts 20.47 KB 20.37 KB +0.10 KB (+0.50%)
schema-toCodeDocument.ts 21.04 KB 20.95 KB +0.09 KB (+0.42%)
schema-toCodecJson.ts 17.62 KB 17.55 KB +0.07 KB (+0.42%)
schema-toEquivalence.ts 17.52 KB 17.44 KB +0.08 KB (+0.44%)
schema-toFormatter.ts 17.37 KB 17.29 KB +0.08 KB (+0.48%)
schema-toJsonSchemaDocument.ts 19.93 KB 19.83 KB +0.10 KB (+0.50%)
schema-toRepresentation.ts 17.92 KB 17.84 KB +0.08 KB (+0.45%)
schema.ts 16.95 KB 16.88 KB +0.07 KB (+0.43%)
stm.ts 11.87 KB 11.76 KB +0.11 KB (+0.93%)
stream.ts 9.20 KB 9.10 KB +0.10 KB (+1.09%)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants